Validator.java

  1. /*
  2.  * GovWay - A customizable API Gateway
  3.  * https://govway.org
  4.  *
  5.  * Copyright (c) 2005-2025 Link.it srl (https://link.it).
  6.  *
  7.  * This program is free software: you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 3, as published by
  9.  * the Free Software Foundation.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  *
  19.  */

  20. package org.openspcoop2.utils.openapi.validator;

  21. import java.io.ByteArrayInputStream;
  22. import java.io.ByteArrayOutputStream;
  23. import java.io.File;
  24. import java.io.InputStream;
  25. import java.math.BigDecimal;
  26. import java.math.RoundingMode;
  27. import java.net.URI;
  28. import java.net.URL;
  29. import java.util.ArrayList;
  30. import java.util.Arrays;
  31. import java.util.HashMap;
  32. import java.util.Iterator;
  33. import java.util.List;
  34. import java.util.Map;
  35. import java.util.Map.Entry;
  36. import java.util.Optional;
  37. import java.util.UUID;
  38. import java.util.function.Function;
  39. import java.util.regex.Matcher;
  40. import java.util.regex.Pattern;

  41. import org.openapi4j.core.model.v3.OAI3Context;
  42. import org.openapi4j.core.model.v3.OAI3SchemaKeywords;
  43. import org.openapi4j.core.util.StringUtil;
  44. import org.openapi4j.core.util.TreeUtil;
  45. import org.openapi4j.core.validation.ValidationResults;
  46. import org.openapi4j.operation.validator.model.Request;
  47. import org.openapi4j.operation.validator.model.Response;
  48. import org.openapi4j.operation.validator.model.impl.Body;
  49. import org.openapi4j.operation.validator.model.impl.DefaultRequest;
  50. import org.openapi4j.operation.validator.model.impl.DefaultResponse;
  51. import org.openapi4j.operation.validator.validation.OperationValidator;
  52. import org.openapi4j.parser.model.v3.OpenApi3;
  53. import org.openapi4j.parser.model.v3.Operation;
  54. import org.openapi4j.parser.model.v3.Path;
  55. import org.openapi4j.parser.validation.v3.OpenApi3Validator;
  56. import org.openapi4j.schema.validator.ValidationData;
  57. import org.openspcoop2.utils.SemaphoreLock;
  58. import org.openspcoop2.utils.date.DateUtils;
  59. import org.openspcoop2.utils.json.AbstractUtils;
  60. import org.openspcoop2.utils.json.IJsonSchemaValidator;
  61. import org.openspcoop2.utils.json.JSONUtils;
  62. import org.openspcoop2.utils.json.JsonPathExpressionEngine;
  63. import org.openspcoop2.utils.json.JsonSchemaValidatorConfig;
  64. import org.openspcoop2.utils.json.JsonSchemaValidatorConfig.ADDITIONAL;
  65. import org.openspcoop2.utils.json.JsonSchemaValidatorConfig.POLITICA_INCLUSIONE_TIPI;
  66. import org.openspcoop2.utils.json.JsonValidatorAPI.ApiName;
  67. import org.openspcoop2.utils.json.ValidationException;
  68. import org.openspcoop2.utils.json.ValidationResponse;
  69. import org.openspcoop2.utils.json.ValidationResponse.ESITO;
  70. import org.openspcoop2.utils.json.ValidatorFactory;
  71. import org.openspcoop2.utils.json.YAMLUtils;
  72. import org.openspcoop2.utils.openapi.OpenapiApi;
  73. import org.openspcoop2.utils.openapi.OpenapiApiValidatorStructure;
  74. import org.openspcoop2.utils.openapi.UniqueInterfaceGenerator;
  75. import org.openspcoop2.utils.openapi.UniqueInterfaceGeneratorConfig;
  76. import org.openspcoop2.utils.openapi.validator.swagger.SwaggerOpenApiValidator;
  77. import org.openspcoop2.utils.openapi.validator.swagger.SwaggerRequestValidator;
  78. import org.openspcoop2.utils.openapi.validator.swagger.SwaggerResponseValidator;
  79. import org.openspcoop2.utils.regexp.RegularExpressionEngine;
  80. import org.openspcoop2.utils.resources.Charset;
  81. import org.openspcoop2.utils.resources.FileSystemUtilities;
  82. import org.openspcoop2.utils.rest.AbstractApiValidator;
  83. import org.openspcoop2.utils.rest.ApiFormats;
  84. import org.openspcoop2.utils.rest.ApiParameterType;
  85. import org.openspcoop2.utils.rest.ApiValidatorConfig;
  86. import org.openspcoop2.utils.rest.IApiValidator;
  87. import org.openspcoop2.utils.rest.ProcessingException;
  88. import org.openspcoop2.utils.rest.ValidatorException;
  89. import org.openspcoop2.utils.rest.api.Api;
  90. import org.openspcoop2.utils.rest.api.ApiBodyParameter;
  91. import org.openspcoop2.utils.rest.api.ApiOperation;
  92. import org.openspcoop2.utils.rest.api.ApiReference;
  93. import org.openspcoop2.utils.rest.api.ApiResponse;
  94. import org.openspcoop2.utils.rest.api.ApiSchema;
  95. import org.openspcoop2.utils.rest.api.ApiSchemaType;
  96. import org.openspcoop2.utils.rest.api.ApiSchemaTypeRestriction;
  97. import org.openspcoop2.utils.rest.entity.Cookie;
  98. import org.openspcoop2.utils.rest.entity.HttpBaseEntity;
  99. import org.openspcoop2.utils.rest.entity.HttpBaseRequestEntity;
  100. import org.openspcoop2.utils.rest.entity.HttpBaseResponseEntity;
  101. import org.openspcoop2.utils.transport.TransportUtils;
  102. import org.openspcoop2.utils.transport.http.HttpConstants;
  103. import org.openspcoop2.utils.transport.http.HttpRequestMethod;
  104. import org.openspcoop2.utils.xml.XMLUtils;
  105. import org.slf4j.Logger;
  106. import org.w3c.dom.Document;
  107. import org.w3c.dom.Element;

  108. import com.atlassian.oai.validator.model.ApiPath;
  109. import com.atlassian.oai.validator.model.ApiPathImpl;
  110. import com.atlassian.oai.validator.model.NormalisedPath;
  111. import com.atlassian.oai.validator.model.NormalisedPathImpl;
  112. import com.atlassian.oai.validator.model.Request.Method;
  113. import com.atlassian.oai.validator.model.SimpleRequest;
  114. import com.atlassian.oai.validator.model.SimpleResponse;
  115. import com.atlassian.oai.validator.report.SimpleValidationReportFormat;
  116. import com.atlassian.oai.validator.report.ValidationReport;
  117. import com.fasterxml.jackson.databind.JsonNode;
  118. import com.fasterxml.jackson.databind.node.ObjectNode;
  119. import com.fasterxml.jackson.databind.node.TextNode;
  120. import com.networknt.schema.SpecVersion.VersionFlag;

  121. import io.swagger.v3.core.util.Json;
  122. import io.swagger.v3.oas.models.OpenAPI;
  123. import io.swagger.v3.oas.models.PathItem;
  124. import io.swagger.v3.oas.models.PathItem.HttpMethod;
  125. import io.swagger.v3.oas.models.headers.Header;
  126. import io.swagger.v3.oas.models.media.ArraySchema;
  127. import io.swagger.v3.oas.models.media.ComposedSchema;
  128. import io.swagger.v3.oas.models.media.Content;
  129. import io.swagger.v3.oas.models.media.MediaType;
  130. import io.swagger.v3.oas.models.media.ObjectSchema;
  131. import io.swagger.v3.oas.models.media.Schema;
  132. import io.swagger.v3.oas.models.media.StringSchema;
  133. import io.swagger.v3.oas.models.parameters.Parameter;
  134. import io.swagger.v3.oas.models.parameters.RequestBody;

  135. /**
  136.  * Validator
  137.  *
  138.  *
  139.  * @author Poli Andrea (apoli@link.it)
  140.  * @author $Author$
  141.  * @version $Rev$, $Date$
  142.  */
  143. public class Validator extends AbstractApiValidator implements IApiValidator {

  144.     private Api api;
  145.     // JSONSchema Validation
  146.     private Map<String, IJsonSchemaValidator> validatorMap;
  147.     private Map<String, File> fileSchema;
  148.     // OpenAPI4j Validation
  149.     private OpenApi3 openApi4j;
  150.    
  151.     // SwaggerRequestValidator
  152.     private SwaggerRequestValidator swaggerRequestValidator;
  153.     private SwaggerResponseValidator swaggerResponseValidator;
  154.     private OpenAPI openApiSwagger;

  155.     // Configuration
  156.     private OpenapiLibraryValidatorConfig openApi4jConfig;
  157.    
  158.     boolean onlySchemas = false;
  159.    
  160.     private Logger log;
  161.    
  162.     private static final String VALIDATION_STRUCTURE = "VALIDATION_STRUCTURE";
  163.     private static final String VALIDATION_SWAGGER_REQUEST_VALIDATOR_OPENAPI = "VALIDATION_SWAGGER_REQUEST_VALIDATOR_OPENAPI";
  164.     private org.openspcoop2.utils.Semaphore semaphore = new org.openspcoop2.utils.Semaphore("OpenAPIValidator");
  165.    
  166.     @Override
  167.     public void init(Logger log, Api api, ApiValidatorConfig config)
  168.             throws ProcessingException {
  169.        
  170.         this.log = log;
  171.         if(api == null)
  172.             throw new ProcessingException("Api cannot be null");

  173.         // la sincronizzazione sull'API serve per evitare che venga inizializzati più volte in maniera concorrente l'API
  174.         //synchronized (api) {
  175.         SemaphoreLock lock = this.semaphore.acquireThrowRuntime("init");
  176.         try {
  177.                    
  178.             this.api = api;
  179.             Api apiRest = null;
  180.             OpenapiApi openapiApi = null;
  181.             OpenapiApiValidatorStructure apiValidatorStructure = null;
  182.             SwaggerRequestValidatorOpenAPI swaggerRequestValidatorOpenAPI = null;
  183.             if((api instanceof OpenapiApi)) {
  184.                 openapiApi = (OpenapiApi) this.api;
  185.                 apiRest = this.api;
  186.                 apiValidatorStructure = openapiApi.getValidationStructure();
  187.                 if(apiRest.containsKey(VALIDATION_SWAGGER_REQUEST_VALIDATOR_OPENAPI)) {
  188.                     swaggerRequestValidatorOpenAPI = (SwaggerRequestValidatorOpenAPI) apiRest.getVendorImpl(VALIDATION_SWAGGER_REQUEST_VALIDATOR_OPENAPI);
  189.                 }
  190.             }
  191.             else {
  192.                 apiRest = this.api;
  193.                 if(apiRest.containsKey(VALIDATION_STRUCTURE)) {
  194.                     apiValidatorStructure = (OpenapiApiValidatorStructure) apiRest.getVendorImpl(VALIDATION_STRUCTURE);
  195.                 }
  196.                 this.onlySchemas = true;
  197.             }
  198.            
  199.             ApiName jsonValidatorAPI = null;
  200.             OpenAPILibrary openApiLibrary = null; // ottimizzazione per OpenAPI
  201.             ADDITIONAL policyAdditionalProperties = config.getPolicyAdditionalProperties();
  202.             if(config instanceof OpenapiApiValidatorConfig) {
  203.                 jsonValidatorAPI = ((OpenapiApiValidatorConfig)config).getJsonValidatorAPI();
  204.                 if(openapiApi!=null) {
  205.                     OpenapiApiValidatorConfig c = (OpenapiApiValidatorConfig) config;
  206.                     if(c.getOpenApiValidatorConfig()!=null) {
  207.                         openApiLibrary = c.getOpenApiValidatorConfig().getOpenApiLibrary();
  208.                         if(OpenAPILibrary.openapi4j.equals(openApiLibrary) || OpenAPILibrary.swagger_request_validator.equals(openApiLibrary)) {
  209.                             this.openApi4jConfig = c.getOpenApiValidatorConfig();
  210.                         }
  211.                     }
  212.                 }
  213.             }
  214.             if(jsonValidatorAPI==null) {
  215.                 jsonValidatorAPI = ApiName.NETWORK_NT;
  216.             }

  217.             try {
  218.            
  219.                 if(OpenAPILibrary.openapi4j.equals(openApiLibrary) ||
  220.                         OpenAPILibrary.swagger_request_validator.equals(openApiLibrary)) {
  221.                    
  222.                     // leggo JSON Node degli schemi
  223.                    
  224.                     JsonNode schemaNodeRoot = null;
  225.                     URL uriSchemaNodeRoot = null;
  226.                     Map<URL, JsonNode> schemaMap = null;
  227.                     String root = "file:/";
  228.                     boolean validateSchema = true;
  229.                     if(apiValidatorStructure!=null && apiValidatorStructure.getNodeValidatorePrincipale()!=null && !apiValidatorStructure.getNodeValidatorePrincipale().isEmpty()) {
  230.                         validateSchema = false; // validazione dello schema effettuata quando viene costruito
  231.                         for (String nome : apiValidatorStructure.getNodeValidatorePrincipale().keySet()) {
  232.                             if(root.equals(nome)) {
  233.                                 schemaNodeRoot = apiValidatorStructure.getNodeValidatorePrincipale().get(nome);
  234.                                 uriSchemaNodeRoot = new URL(root);
  235.                             }
  236.                             else {
  237.                                 if(schemaMap==null) {
  238.                                     schemaMap = new HashMap<URL, JsonNode>();
  239.                                 }
  240.                                 schemaMap.put(new URL(nome), apiValidatorStructure.getNodeValidatorePrincipale().get(nome));
  241.                             }
  242.                         }
  243.                     }
  244.                     else {
  245.                        
  246.                         YAMLUtils yamlUtils = YAMLUtils.getInstance();
  247.                         JSONUtils jsonUtils = JSONUtils.getInstance();
  248.                                                
  249.                         String apiRaw = openapiApi.getApiRaw();
  250.                         boolean apiRawIsYaml = yamlUtils.isYaml(apiRaw);
  251.                         boolean readApiSchemas = true;
  252.                         if(this.openApi4jConfig.isMergeAPISpec()) {
  253.                            
  254.                             readApiSchemas = false;
  255.                            
  256.                             Map<String, String> attachments = new HashMap<>();
  257.                             if(api.getSchemas()!=null && api.getSchemas().size()>0) {

  258.                                 for (ApiSchema apiSchema : api.getSchemas()) {
  259.                                
  260.                                     if(!ApiSchemaType.JSON.equals(apiSchema.getType()) && !ApiSchemaType.YAML.equals(apiSchema.getType())) {
  261.                                         continue;
  262.                                     }
  263.                                     byte [] schema = apiSchema.getContent();
  264.                                     if(ApiSchemaType.JSON.equals(apiSchema.getType())) {
  265.                                         if(jsonUtils.isJson(schema)) {
  266.                                             attachments.put(apiSchema.getName(), new String(apiSchema.getContent()));
  267.                                         }
  268.                                     }
  269.                                     else {
  270.                                         if(yamlUtils.isYaml(schema)) {
  271.                                             attachments.put(apiSchema.getName(), new String(apiSchema.getContent()));
  272.                                         }
  273.                                     }
  274.                                    
  275.                                 }
  276.                             }
  277.                            
  278.                             if(!attachments.isEmpty()) {                            
  279.                                 UniqueInterfaceGeneratorConfig configUniqueInterfaceGeneratorConfig = new UniqueInterfaceGeneratorConfig();
  280.                                 configUniqueInterfaceGeneratorConfig.setFormat(ApiFormats.OPEN_API_3);
  281.                                 configUniqueInterfaceGeneratorConfig.setYaml(apiRawIsYaml);
  282.                                 configUniqueInterfaceGeneratorConfig.setMaster(apiRaw);
  283.                                 configUniqueInterfaceGeneratorConfig.setAttachments(attachments);
  284.                                 try {
  285.                                     String apiMerged = UniqueInterfaceGenerator.generate(configUniqueInterfaceGeneratorConfig, null, null, true, log);
  286.                                     if(apiMerged==null) {
  287.                                         throw new Exception("empty ApiSpec");
  288.                                     }
  289.                                     apiRaw = apiMerged;
  290.                                 }catch(Throwable t) {
  291.                                     log.error("Merge API Spec failed: "+t.getMessage(),t);
  292.                                     readApiSchemas = true; // torno al metodo tradizionale
  293.                                 }
  294.                             }
  295.                         }
  296.                        
  297.                         if(apiRawIsYaml) {
  298.                             // Fix merge key '<<: *'
  299.                             if(YAMLUtils.containsMergeKeyAnchor(apiRaw)) {
  300.                                 // Risoluzione merge key '<<: *'
  301.                                 String jsonRepresentation = YAMLUtils.resolveMergeKeyAndConvertToJson(apiRaw);
  302.                                 schemaNodeRoot = jsonUtils.getAsNode(jsonRepresentation);
  303.                             }
  304.                             else {
  305.                                 schemaNodeRoot = yamlUtils.getAsNode(apiRaw);
  306.                             }
  307.                         }
  308.                         else {
  309.                             schemaNodeRoot = jsonUtils.getAsNode(apiRaw);
  310.                         }
  311.                         normalizeRefs(schemaNodeRoot);
  312.                         uriSchemaNodeRoot = new URL(root);
  313.                        
  314.                         if(readApiSchemas && api.getSchemas()!=null && api.getSchemas().size()>0) {
  315.                            
  316.                             for (ApiSchema apiSchema : api.getSchemas()) {
  317.                                
  318.                                 if(!ApiSchemaType.JSON.equals(apiSchema.getType()) && !ApiSchemaType.YAML.equals(apiSchema.getType())) {
  319.                                     continue;
  320.                                 }
  321.                                 byte [] schema = apiSchema.getContent();
  322.                                 JsonNode schemaNodeInternal = null;
  323.                                 if(ApiSchemaType.JSON.equals(apiSchema.getType())) {
  324.                                     if(jsonUtils.isJson(schema)) {
  325.                                         schemaNodeInternal = jsonUtils.getAsNode(schema);
  326.                                     }
  327.                                 }
  328.                                 else {
  329.                                     if(yamlUtils.isYaml(schema)) {
  330.                                         // Vedi fix descritto sopra
  331.                                         String sSchema = new String(schema);
  332.                                         // Fix merge key '<<: *'
  333.                                         if(YAMLUtils.containsMergeKeyAnchor(sSchema)) {
  334.                                             // Risoluzione merge key '<<: *'
  335.                                             String jsonRepresentation = YAMLUtils.resolveMergeKeyAndConvertToJson(sSchema);
  336.                                             schemaNodeInternal = jsonUtils.getAsNode(jsonRepresentation);
  337.                                         }
  338.                                         else {
  339.                                             schemaNodeInternal = yamlUtils.getAsNode(schema);
  340.                                         }
  341.                                     }
  342.                                 }
  343.                                 if(schemaNodeInternal==null) {
  344.                                     continue;
  345.                                 }
  346.                                 normalizeRefs(schemaNodeInternal);
  347.                                 if(schemaMap==null) {
  348.                                     schemaMap = new HashMap<URL, JsonNode>();
  349.                                 }
  350.                                 schemaMap.put(new URL(root+apiSchema.getName()), schemaNodeInternal);
  351.                                
  352.                             }
  353.                            
  354.                         }
  355.                     }

  356.                     if(OpenAPILibrary.openapi4j.equals(openApiLibrary)) {
  357.                    
  358.                         // Costruisco OpenAPI3                  
  359.                         OAI3Context context = new OAI3Context(uriSchemaNodeRoot, schemaNodeRoot, schemaMap);
  360.                         if(this.openApi4jConfig!=null) {
  361.                             context.setMultipartOptimization(this.openApi4jConfig.isValidateMultipartOptimization());
  362.                         }
  363.                         this.openApi4j = TreeUtil.json.convertValue(context.getBaseDocument(), OpenApi3.class);
  364.                         this.openApi4j.setContext(context);
  365.                        
  366.                         // Explicit validation of the API spec
  367.                        
  368.                         if(validateSchema && this.openApi4jConfig!=null && this.openApi4jConfig.isValidateAPISpec()) {
  369.                             try {
  370.                                 ValidationResults results = OpenApi3Validator.instance().validate(this.openApi4j);
  371.                                 if(!results.isValid()) {
  372.                                     throw new ProcessingException("OpenAPI3 not valid: "+results.toString());
  373.                                 }
  374.                             }catch(org.openapi4j.core.validation.ValidationException valExc) {
  375.                                 if(valExc.results()!=null) {
  376.                                     throw new ProcessingException("OpenAPI3 not valid: "+valExc.results().toString());
  377.                                 }
  378.                                 else {
  379.                                     throw new ProcessingException("OpenAPI3 not valid: "+valExc.getMessage());
  380.                                 }
  381.                             }
  382.                         }                      
  383.                     } // fine openapi4j
  384.                    
  385.                     else if(OpenAPILibrary.swagger_request_validator.equals(openApiLibrary)) {
  386.                         // Validazione sintattica se richiesta
  387.                        
  388.                         if(validateSchema && this.openApi4jConfig.isValidateAPISpec()) {
  389.                             var validationResult = new SwaggerOpenApiValidator().validate(schemaNodeRoot);
  390.                             if (validationResult.isPresent()) {
  391.                                 throw new ProcessingException(
  392.                                         "OpenAPI3 not valid: " + validationResult.get()
  393.                                         );                              
  394.                             }                      
  395.                         }
  396.                        
  397.                         // Parsing
  398.                         if(swaggerRequestValidatorOpenAPI!=null) {
  399.                             this.openApiSwagger = swaggerRequestValidatorOpenAPI.getOpenApiSwagger();
  400.                         }
  401.                         else {
  402.                             SwaggerRequestValidatorOpenAPI newInstanceSwaggerRequestValidatorOpenAPI = new SwaggerRequestValidatorOpenAPI(schemaNodeRoot, this.openApi4jConfig, api);
  403.                             this.openApiSwagger = newInstanceSwaggerRequestValidatorOpenAPI.getOpenApiSwagger(); // init
  404.                             apiRest.addVendorImpl(VALIDATION_SWAGGER_REQUEST_VALIDATOR_OPENAPI, newInstanceSwaggerRequestValidatorOpenAPI);
  405.                         }
  406.                        
  407.                         this.swaggerRequestValidator = new SwaggerRequestValidator(this.openApiSwagger, this.openApi4jConfig);
  408.                         this.swaggerResponseValidator = new SwaggerResponseValidator(this.openApiSwagger, this.openApi4jConfig);
  409.                    
  410.                     } // fine swagger_request_validator
  411.                    

  412.                     // Salvo informazioni ricostruite
  413.                     if(apiValidatorStructure==null) {
  414.                         OpenapiApiValidatorStructure validationStructure = new OpenapiApiValidatorStructure();
  415.                         Map<String, JsonNode> nodeValidatorePrincipale = new HashMap<String, JsonNode>();
  416.                         nodeValidatorePrincipale.put(root, schemaNodeRoot);
  417.                         if(schemaMap!=null && !schemaMap.isEmpty()) {
  418.                             for (URL url : schemaMap.keySet()) {
  419.                                 nodeValidatorePrincipale.put(url.toString(), schemaMap.get(url));
  420.                             }
  421.                         }
  422.                         validationStructure.setNodeValidatorePrincipale(nodeValidatorePrincipale);
  423.                         openapiApi.setValidationStructure(validationStructure);
  424.                     }

  425.                     return; // finish
  426.                 }
  427.                
  428.                
  429.                
  430.                 this.validatorMap = new HashMap<>();
  431.                
  432.                
  433.                 // Verifico se gli schemi importati o gli elementi definition dentro l'interfaccia api,
  434.                 // a loro volta importano altri schemi tramite il $ref standard di json schema
  435.                 // Se cosi non è non serve serializzarli su file system, la cui serializzazione è ovviamente più costosa in termini di performance.
  436.                 boolean existsRefInternal = false;
  437.                
  438.                
  439.                
  440.                
  441.                 /* *** Validatore Principale *** */
  442.                
  443.                 Map<String, byte[]> schemiValidatorePrincipale = new HashMap<>();
  444.                 Map<String, JsonNode> nodeValidatorePrincipale = new HashMap<>();
  445.                
  446.                 if(apiValidatorStructure!=null) {
  447.                     schemiValidatorePrincipale = apiValidatorStructure.getSchemiValidatorePrincipale();
  448.                     nodeValidatorePrincipale = apiValidatorStructure.getNodeValidatorePrincipale();
  449.                 }
  450.                 else {

  451.                     if(openapiApi!=null) {

  452.                         Map<String, Schema<?>> definitions = openapiApi.getAllDefinitions();
  453.                         String definitionString = Json.mapper().writeValueAsString(definitions);
  454.                         definitionString = definitionString.replaceAll("#/components/schemas", "#/definitions");
  455.                         for(String schemaName: definitions.keySet()) {
  456.                            
  457.                             ByteArrayOutputStream bout = new ByteArrayOutputStream();
  458.                             bout.write("{".getBytes());
  459.                             String defOggetto = Json.mapper().writeValueAsString(definitions.get(schemaName));
  460.                             defOggetto = defOggetto.trim();
  461.                             defOggetto = defOggetto.replaceAll("#/components/schemas", "#/definitions");
  462.                             if(defOggetto.startsWith("{")) {
  463.                                 defOggetto = defOggetto.substring(1);
  464.                             }
  465.                             if(defOggetto.endsWith("}")) {
  466.                                 defOggetto = defOggetto.substring(0,defOggetto.length()-1);
  467.                             }
  468.                             defOggetto = defOggetto.trim();
  469.                             bout.write(defOggetto.getBytes());
  470.                             // DEVE ESSERE DEFINITO NEL JSON SCHEMA, NON POSSO DEFINIRLO STATICAMENTE
  471.                             /*
  472.                                 bout.write(",\"additionalProperties\": ".getBytes());
  473.                                 if(defOggetto.startsWith("\"allOf\"") || defOggetto.startsWith("\"anyOf\"")){
  474.                                     // INDICARE ARTICOLO CHE SPIEGA
  475.                                     bout.write("true".getBytes());
  476.                                 }
  477.                                 else {
  478.                                     bout.write("false".getBytes());
  479.                                 }
  480.                             */
  481.                             bout.write(",".getBytes());
  482.                             bout.write("\"definitions\" : ".getBytes());
  483.                             bout.write(definitionString.getBytes());
  484.                             bout.write("}".getBytes());
  485.                            
  486.                             // Normalizzo schemi importati
  487.                             JSONUtils jsonUtils = JSONUtils.getInstance();
  488.                             JsonNode schemaNode = jsonUtils.getAsNode(bout.toByteArray());
  489.                             nodeValidatorePrincipale.put(schemaName, schemaNode);
  490.                             schemiValidatorePrincipale.put(schemaName, bout.toByteArray());
  491.                            
  492.                             // Verifico se gli elementi definition, a loro volta importano altri schemi
  493.                             JsonPathExpressionEngine engine = new JsonPathExpressionEngine();
  494.                             List<String> refPath = engine.getStringMatchPattern(schemaNode, "$..$ref");
  495.                             if(refPath!=null && !refPath.isEmpty()) {
  496.                                 for (String ref : refPath) {
  497.                                     String path = this.getRefPath(ref);
  498.                                     if(path!=null) {
  499.                                         existsRefInternal = true;
  500.                                         break;
  501.                                     }
  502.                                 }
  503.                             }
  504.            
  505.                         }
  506.                     }
  507.                 }
  508.                
  509.                
  510.                
  511.                
  512.                
  513.                 // *** Gestione file importati ***
  514.                
  515.                 this.fileSchema = new HashMap<>();
  516.                 if(apiValidatorStructure!=null) {
  517.                     this.fileSchema = apiValidatorStructure.getFileSchema();
  518.                 }
  519.                 else {
  520.                     if(api.getSchemas()!=null && api.getSchemas().size()>0) {
  521.                    
  522.                         HashMap<String, JsonNode> tmpNode = new HashMap<>();
  523.                         HashMap<String, byte[]> tmpByteArraySchema = new HashMap<>();
  524.                         HashMap<String, ApiSchemaType> tmpSchemaType = new HashMap<>();
  525.                        
  526.                         for (ApiSchema apiSchema : api.getSchemas()) {
  527.                            
  528.                             if(!ApiSchemaType.JSON.equals(apiSchema.getType()) && !ApiSchemaType.YAML.equals(apiSchema.getType())) {
  529.                                
  530.                                 continue;
  531.                                
  532.                             }
  533.                             byte [] schema = apiSchema.getContent();
  534.                             JsonNode schemaNode = null;
  535.                             AbstractUtils utils = null;
  536.                             JSONUtils jsonUtils = JSONUtils.getInstance();
  537.                             if(ApiSchemaType.JSON.equals(apiSchema.getType())) {
  538.                                 utils = JSONUtils.getInstance();
  539.                                 if(((JSONUtils)utils).isJson(schema)) {
  540.                                     schemaNode = utils.getAsNode(schema);
  541.                                 }
  542.                             }
  543.                             else {
  544.                                 utils = YAMLUtils.getInstance();
  545.                                 if(((YAMLUtils)utils).isYaml(schema)) {
  546.                                     schemaNode = utils.getAsNode(schema);
  547.                                 }
  548.                             }
  549.                             if(schemaNode==null) {
  550.                                 continue;
  551.                             }
  552.                            
  553.                            
  554.                             /* ** Potenziale import from swagger/openapi che utilizza uno standard components/schema invece di definition, ed inoltre non inizia con { } **/
  555.                             if(schemaNode instanceof TextNode) {
  556.                                 ByteArrayOutputStream bout = new ByteArrayOutputStream();
  557.                                 bout.write("{".getBytes());
  558.                                 bout.write(schema);
  559.                                 bout.write("}".getBytes());
  560.                                 bout.flush();
  561.                                 bout.close();
  562.                                 schemaNode = utils.getAsNode(bout.toByteArray());
  563.                             }
  564.                             if(schemaNode instanceof ObjectNode) {
  565.                                 ObjectNode objectNode = (ObjectNode) schemaNode;
  566.                                
  567.                                 boolean foundDefinitions = false;
  568.                                 JsonNode nodeDefinitions = objectNode.get("definitions");
  569.                                 if(nodeDefinitions!=null && nodeDefinitions instanceof ObjectNode) {
  570.                                     foundDefinitions = true;
  571.                                 }
  572.                                
  573.                                 if(!foundDefinitions) {
  574.                                     JsonNode nodeComponents = objectNode.get("components");
  575.                                     if(nodeComponents instanceof ObjectNode) {
  576.                                         ObjectNode objectNodeComponents = (ObjectNode) nodeComponents;
  577.                                         JsonNode nodeSchemas = objectNodeComponents.get("schemas");
  578.                                         if(nodeSchemas!=null && nodeSchemas instanceof ObjectNode) {
  579.                                            
  580.                                             ObjectNode objectNodeDefinitions = (ObjectNode) utils.newObjectNode();
  581.                                             objectNodeDefinitions.set("definitions", nodeSchemas);
  582.                                             String schemaAsString = null;
  583.                                             if(ApiSchemaType.YAML.equals(apiSchema.getType())) {
  584.                                                 // converto comunque in json poichè la validazione è supportata per json solo
  585.                                                 schemaAsString = jsonUtils.toString(objectNodeDefinitions);
  586.                                             }
  587.                                             else {
  588.                                                 schemaAsString = utils.toString(objectNodeDefinitions);
  589.                                             }
  590.                                             schemaAsString = schemaAsString.replaceAll("#/components/schemas", "#/definitions");
  591.                                             schema = schemaAsString.getBytes();
  592.                                             schemaNode = objectNodeDefinitions;
  593.                                             //System.out.println("SCHEMA ["+new String(schema)+"]");
  594.                                            
  595.                                         }
  596.                                         else {
  597.                                             schema = null;
  598.                                             schemaNode = null;
  599.                                         }
  600.                                     }
  601.                                 }
  602.                             }
  603.                            
  604.                             if(schemaNode!=null) {
  605.                                 if(this.onlySchemas) {
  606.                                    
  607.                                     // Interfaccia Registro senza OpenAPI
  608.                                    
  609.                                     IJsonSchemaValidator validator = ValidatorFactory.newJsonSchemaValidator(jsonValidatorAPI);
  610.                                     JsonSchemaValidatorConfig schemaValidationConfig = new JsonSchemaValidatorConfig();
  611.                                     schemaValidationConfig.setVerbose(config.isVerbose());
  612.                                     schemaValidationConfig.setAdditionalProperties(policyAdditionalProperties);
  613.                                     schemaValidationConfig.setPoliticaInclusioneTipi(POLITICA_INCLUSIONE_TIPI.DEFAULT);
  614.                                     schemaValidationConfig.setEmitLogError(config.isEmitLogError());
  615.                                     schemaValidationConfig.setJsonSchemaVersion(VersionFlag.V4); // https://github.com/OAI/OpenAPI-Specification/blob/main/schemas/v3.0/schema.json
  616.                                     //System.out.println("ADD SCHEMA PER ["+apiSchemaName+"#"+nameInternal+"] ["+new String(bout.toByteArray())+"]");
  617.                                     validator.setSchema(schema, schemaValidationConfig, log);
  618.                                    
  619.                                     this.validatorMap.put(apiSchema.getName(), validator);
  620.                                    
  621.                                 }
  622.                                 else {
  623.        
  624.                                     File tmp = FileSystemUtilities.createTempFile("validator", "."+ apiSchema.getType().name().toLowerCase());
  625.                                     this.fileSchema.put(apiSchema.getName(), tmp);
  626.                                     tmpNode.put(apiSchema.getName(), schemaNode);
  627.                                     tmpByteArraySchema.put(apiSchema.getName(), schema);
  628.                                     tmpSchemaType.put(apiSchema.getName(), apiSchema.getType());
  629.                                    
  630.                                 }
  631.                             }
  632.                         }
  633.                        
  634.                        
  635.                         if(!this.onlySchemas) {
  636.                        
  637.                             // Verifico se gli schemi importati, a loro volta importano altri schemi
  638.                             // Se cosi non è non serve serializzarli su file system
  639.                             if(!existsRefInternal && !tmpByteArraySchema.isEmpty()) {
  640.                                 Iterator<String> itSchemas = tmpByteArraySchema.keySet().iterator();
  641.                                 while (itSchemas.hasNext()) {
  642.                                     String apiSchemaName = (String) itSchemas.next();
  643.                                     JsonNode schemaNode = tmpNode.get(apiSchemaName);
  644.                                     JsonPathExpressionEngine engine = new JsonPathExpressionEngine();
  645.                                     List<String> refPath = engine.getStringMatchPattern(schemaNode, "$..$ref");
  646.                                     if(refPath!=null && !refPath.isEmpty()) {
  647.                                         for (String ref : refPath) {
  648.                                             String path = this.getRefPath(ref);
  649.                                             if(path!=null) {
  650.                                                 existsRefInternal = true;
  651.                                                 break;
  652.                                             }
  653.                                         }
  654.                                     }
  655.                                     if(existsRefInternal) {
  656.                                         break;
  657.                                     }
  658.                                 }
  659.                             }
  660.                            
  661.                             if(existsRefInternal && !tmpByteArraySchema.isEmpty()) {
  662.                                 Iterator<String> itSchemas = tmpByteArraySchema.keySet().iterator();
  663.                                 while (itSchemas.hasNext()) {
  664.                                     String apiSchemaName = (String) itSchemas.next();
  665.                                     JsonNode schemaNode = tmpNode.get(apiSchemaName);
  666.                                     byte [] schemaContent = tmpByteArraySchema.get(apiSchemaName);
  667.                                    
  668.                                     JsonPathExpressionEngine engine = new JsonPathExpressionEngine();
  669.                                     List<String> refPath = engine.getStringMatchPattern(schemaNode, "$..$ref");
  670.                                     String schemaRebuild = null;
  671.                                     if(refPath!=null && !refPath.isEmpty()) {
  672.                                         for (String ref : refPath) {
  673.                                             String path = this.getRefPath(ref);
  674.                                             if(path!=null) {
  675.                                                 String normalizePath = this.normalizePath(path);
  676.                                                 if(normalizePath!=null && this.fileSchema.containsKey(normalizePath)) {
  677.                                                     if(schemaRebuild==null) {
  678.                                                         schemaRebuild = new String(schemaContent);
  679.                                                     }
  680.                                                     if(schemaRebuild.contains(path)==false) {
  681.                                                         if(path.startsWith("./")) {
  682.                                                             path = path.substring(2);
  683.                                                         }
  684.                                                     }
  685.                                                     File file = this.fileSchema.get(normalizePath);
  686.                                                     while(schemaRebuild.contains(path)) {
  687.                                                         schemaRebuild = schemaRebuild.replace(path, "file://"+file.getAbsolutePath());
  688.                                                     }
  689.                                                 }
  690.                                             }
  691.                                         }
  692.                                     }
  693.                                    
  694.                                     File f = this.fileSchema.get(apiSchemaName);
  695.                                     if(schemaRebuild!=null) {
  696.                                         FileSystemUtilities.writeFile(f, schemaRebuild.getBytes());
  697.                                         AbstractUtils utils = null;
  698.                                         if(ApiSchemaType.JSON.equals(tmpSchemaType.get(apiSchemaName))) {
  699.                                             utils = JSONUtils.getInstance();
  700.                                         }
  701.                                         else {
  702.                                             utils = YAMLUtils.getInstance();
  703.                                         }
  704.                                         schemaNode = utils.getAsNode(schemaRebuild);
  705.                                         tmpNode.put(apiSchemaName, schemaNode);
  706.                                         tmpByteArraySchema.put(apiSchemaName,schemaRebuild.getBytes());
  707.                                     }
  708.                                     else {
  709.                                         FileSystemUtilities.writeFile(f, schemaContent);
  710.                                     }
  711.                                 }
  712.                                    
  713.                                
  714.                                 if(!tmpByteArraySchema.isEmpty()) {
  715.                                     itSchemas = tmpByteArraySchema.keySet().iterator();
  716.                                     while (itSchemas.hasNext()) {
  717.                                         String apiSchemaName = (String) itSchemas.next();
  718.                                         JsonNode schemaNode = tmpNode.get(apiSchemaName);
  719.                                         if(schemaNode instanceof ObjectNode) {
  720.                                             ObjectNode objectNode = (ObjectNode) schemaNode;
  721.                                             Iterator<String> it = objectNode.fieldNames();
  722.                                             String name = null;
  723.                                             while (it.hasNext()) {
  724.                                                 name = (String) it.next();
  725.                                                 if("definitions".equalsIgnoreCase(name)) {
  726.                                                     JsonNode internalNode = objectNode.get(name);
  727.                                                     if(internalNode instanceof ObjectNode) {
  728.                                                         ObjectNode internalObjectNode = (ObjectNode) internalNode;
  729.                                                         Iterator<String> itInternal = internalObjectNode.fieldNames();
  730.                                                         while (itInternal.hasNext()) {
  731.                                                             String nameInternal = (String) itInternal.next();
  732.                                                             JsonNode typeDefinition = internalObjectNode.get(nameInternal);
  733.                                                            
  734.                                                             ByteArrayOutputStream bout = new ByteArrayOutputStream();
  735.                                                             bout.write("{".getBytes());
  736.                                                             String defOggetto = JSONUtils.getInstance().toString(typeDefinition);
  737.                                                             defOggetto = defOggetto.trim();
  738.                                                             defOggetto = defOggetto.replaceAll("#/components/schemas", "#/definitions");
  739.                                                             if(defOggetto.startsWith("{")) {
  740.                                                                 defOggetto = defOggetto.substring(1);
  741.                                                             }
  742.                                                             if(defOggetto.endsWith("}")) {
  743.                                                                 defOggetto = defOggetto.substring(0,defOggetto.length()-1);
  744.                                                             }
  745.                                                             defOggetto = defOggetto.trim();
  746.                                                             bout.write(defOggetto.getBytes());
  747.                                                             // DEVE ESSERE DEFINITO NEL JSON SCHEMA, NON POSSO DEFINIRLO STATICAMENTE
  748.                                                             /*
  749.                                                             bout.write(",\"additionalProperties\": ".getBytes());
  750.                                                             if(defOggetto.startsWith("\"allOf\"") || defOggetto.startsWith("\"anyOf\"")){
  751.                                                                 // INDICARE ARTICOLO CHE SPIEGA
  752.                                                                 bout.write("true".getBytes());
  753.                                                             }
  754.                                                             else {
  755.                                                                 bout.write("false".getBytes());
  756.                                                             }*/
  757.                                                             bout.write(",".getBytes());
  758.                                                             bout.write("\"definitions\" : ".getBytes());
  759.                                                             String definitionStringSchema = JSONUtils.getInstance().toString(internalNode);
  760.                                                             definitionStringSchema = definitionStringSchema.replaceAll("#/components/schemas", "#/definitions");
  761.                                                             bout.write(definitionStringSchema.getBytes());
  762.                                                             bout.write("}".getBytes());
  763.                                                                                                    
  764.                                                             IJsonSchemaValidator validator = ValidatorFactory.newJsonSchemaValidator(jsonValidatorAPI);
  765.                                                             JsonSchemaValidatorConfig schemaValidationConfig = new JsonSchemaValidatorConfig();
  766.                                                             schemaValidationConfig.setVerbose(config.isVerbose());
  767.                                                             schemaValidationConfig.setAdditionalProperties(policyAdditionalProperties);
  768.                                                             schemaValidationConfig.setPoliticaInclusioneTipi(POLITICA_INCLUSIONE_TIPI.DEFAULT);
  769.                                                             schemaValidationConfig.setEmitLogError(config.isEmitLogError());
  770.                                                             schemaValidationConfig.setJsonSchemaVersion(VersionFlag.V4); // https://github.com/OAI/OpenAPI-Specification/blob/main/schemas/v3.0/schema.json
  771.                                                             //System.out.println("ADD SCHEMA PER ["+apiSchemaName+"#"+nameInternal+"] ["+new String(bout.toByteArray())+"]");
  772.                                                             validator.setSchema(bout.toByteArray(), schemaValidationConfig, log);
  773.                                                            
  774.                                                             this.validatorMap.put(apiSchemaName+"#"+nameInternal, validator);
  775.                                                            
  776.                                                         }
  777.                                                     }
  778.                                                 }
  779.                                             }
  780.                                         }
  781.                                    
  782.                                     }
  783.                                    
  784.                                 }
  785.                                
  786.                             }
  787.                         }
  788.                     }
  789.                 }
  790.                
  791.                
  792.                 /* *** Validatore Principale *** */
  793.                
  794.                 if(apiValidatorStructure!=null) {
  795.                     this.validatorMap = apiValidatorStructure.getValidatorMap();
  796.                 }
  797.                 else {
  798.                     if(schemiValidatorePrincipale!=null && schemiValidatorePrincipale.size()>0) {
  799.                         Iterator<String> it = schemiValidatorePrincipale.keySet().iterator();
  800.                         while (it.hasNext()) {
  801.                             String schemaName = (String) it.next();
  802.                             byte [] schema = schemiValidatorePrincipale.get(schemaName);
  803.                             JsonNode schemaNode = nodeValidatorePrincipale.get(schemaName);
  804.                        
  805.                             JsonPathExpressionEngine engine = new JsonPathExpressionEngine();
  806.                             List<String> refPath = engine.getStringMatchPattern(schemaNode, "$..$ref");
  807.                             String schemaRebuild = null;
  808.                             if(refPath!=null && !refPath.isEmpty()) {
  809.                                 for (String ref : refPath) {
  810.                                     String path = this.getRefPath(ref);
  811.                                     if(path!=null) {
  812.                                         String normalizePath = this.normalizePath(path);
  813.                                         if(normalizePath!=null && this.fileSchema.containsKey(normalizePath)) {
  814.                                             if(schemaRebuild==null) {
  815.                                                 schemaRebuild = new String(schema);
  816.                                             }
  817.                                             if(schemaRebuild.contains(path)==false) {
  818.                                                 if(path.startsWith("./")) {
  819.                                                     path = path.substring(2);
  820.                                                 }
  821.                                             }
  822.                                             File file = this.fileSchema.get(normalizePath);
  823.                                             while(schemaRebuild.contains(path)) {
  824.                                                 schemaRebuild = schemaRebuild.replace(path, "file://"+file.getAbsolutePath());
  825.                                             }
  826.                                         }
  827.                                     }
  828.                                 }
  829.                             }
  830.                             if(schemaRebuild!=null) {
  831.                                 schema = schemaRebuild.getBytes();
  832.                             }      
  833.                            
  834.                             // Costruisco validatore
  835.                             IJsonSchemaValidator validator = ValidatorFactory.newJsonSchemaValidator(jsonValidatorAPI);
  836.                             JsonSchemaValidatorConfig schemaValidationConfig = new JsonSchemaValidatorConfig();
  837.                             schemaValidationConfig.setVerbose(config.isVerbose());
  838.                             schemaValidationConfig.setAdditionalProperties(policyAdditionalProperties);
  839.                             schemaValidationConfig.setPoliticaInclusioneTipi(POLITICA_INCLUSIONE_TIPI.DEFAULT);
  840.                             schemaValidationConfig.setEmitLogError(config.isEmitLogError());
  841.                             schemaValidationConfig.setJsonSchemaVersion(VersionFlag.V4); // https://github.com/OAI/OpenAPI-Specification/blob/main/schemas/v3.0/schema.json
  842.                             //System.out.println("ADD SCHEMA PER ["+schemaName+"] ["+new String(schema)+"]");
  843.                             validator.setSchema(schema, schemaValidationConfig, log);
  844.                            
  845.                             this.validatorMap.put(schemaName, validator);
  846.                         }
  847.                     }
  848.                 }
  849.                
  850.                
  851.                
  852.                 // Salvo informazioni ricostruite
  853.                 if(apiValidatorStructure==null) {
  854.                     OpenapiApiValidatorStructure validationStructure = new OpenapiApiValidatorStructure();
  855.                     validationStructure.setSchemiValidatorePrincipale(schemiValidatorePrincipale);
  856.                     validationStructure.setNodeValidatorePrincipale(nodeValidatorePrincipale);
  857.                     validationStructure.setFileSchema(this.fileSchema);
  858.                     validationStructure.setValidatorMap(this.validatorMap);
  859.                     if(openapiApi!=null) {
  860.                         openapiApi.setValidationStructure(validationStructure);
  861.                     }
  862.                     else if(apiRest!=null) {
  863.                         apiRest.addVendorImpl(VALIDATION_STRUCTURE, validationStructure);
  864.                     }
  865.                 }
  866.                
  867.                                
  868.             } catch(Throwable e) {
  869.                 try {
  870.                     this.close(log, api, config); // per chiudere eventuali risorse parzialmente inizializzate
  871.                 }catch(Throwable t) {}
  872.                
  873.                 throw new ProcessingException(e);
  874.             }
  875.            
  876.         }finally {
  877.             this.semaphore.release(lock, "init");
  878.         }
  879.     }

  880.     private String getRefPath(String ref) {
  881.         if(ref.trim().startsWith("#")) {
  882.             return null;
  883.         }
  884.         return ref.trim().substring(0, ref.indexOf("#"));
  885.     }
  886.     private static String getRefType(String ref) {
  887.         if(ref.trim().startsWith("#")) {
  888.             return ref;
  889.         }
  890.         return ref.trim().substring(ref.indexOf("#"), ref.length());
  891.     }
  892.     private String normalizePath(String path) throws ProcessingException {
  893.         if(path.startsWith("http://") || path.startsWith("https://") || path.startsWith("file://")){    
  894.             try {
  895.                 URL url = new URL(path);
  896.                 File fileUrl = new File(url.getFile());
  897.                 return fileUrl.getName();
  898.             }catch(Exception e) {
  899.                 throw new ProcessingException(e.getMessage(),e);
  900.             }
  901.         }
  902.         else{
  903.             File f = new File(path);
  904.             return f.getName();
  905.         }
  906.     }
  907.     private void normalizeRefs(JsonNode node) throws ProcessingException {
  908.         List<JsonNode> listRef = node.findParents(OAI3SchemaKeywords.$REF);
  909.         if(listRef!=null) {
  910.             for (JsonNode jsonNodeRef : listRef) {
  911.                 //System.out.println("REF ("+jsonNodeRef.getClass().getName()+") : "+jsonNodeRef);
  912.                 if(jsonNodeRef instanceof ObjectNode) {
  913.                     ObjectNode oNode = (ObjectNode) jsonNodeRef;
  914.                     JsonNode valore = oNode.get(OAI3SchemaKeywords.$REF);
  915.                     String ref = valore.asText();
  916.                     //System.out.println("VALORE:"+v);
  917.                     String path = getRefPath(ref);
  918.                     if(path!=null) {
  919.                         String normalizePath = normalizePath(path);
  920.                         String refType = getRefType(ref);
  921.                         //System.out.println("REF ("+jsonNodeRef.getClass().getName()+") : "+jsonNodeRef);
  922.                         //System.out.println("Tipo ("+refType+") VALORE:"+normalizePath);
  923.                         oNode.remove(OAI3SchemaKeywords.$REF);
  924.                         oNode.put(OAI3SchemaKeywords.$REF, normalizePath+refType);
  925.                     }
  926.                 }
  927.             }
  928.         }
  929.     }
  930.    
  931.     @Override
  932.     public void close(Logger log, Api api, ApiValidatorConfig config) throws ProcessingException{
  933.         if(this.fileSchema!=null) {
  934.             Iterator<String> itFiles = this.fileSchema.keySet().iterator();
  935.             while (itFiles.hasNext()) {
  936.                 String key = (String) itFiles.next();
  937.                 File file = this.fileSchema.get(key);
  938.                 if(file.delete()==false) {
  939.                     log.error("Eliminazione file temporaneo ["+file.getAbsolutePath()+"] associato allo schema ["+key+"] non riuscita");
  940.                 }
  941.             }
  942.         }
  943.     }
  944.    
  945.     @Override
  946.     public void validate(HttpBaseEntity<?> httpEntity)
  947.             throws ProcessingException, ValidatorException {
  948.         List<Object> args = new ArrayList<>();
  949.         super.validate(this.api, httpEntity, args);
  950.     }

  951.     private List<ApiBodyParameter> getBodyParameters(HttpBaseEntity<?> httpEntity, ApiOperation operation){
  952.         List<ApiBodyParameter> bodyParameters = null;
  953.         if(httpEntity instanceof HttpBaseRequestEntity) {
  954.             if(operation.getRequest()!=null) {
  955.                 bodyParameters = operation.getRequest().getBodyParameters();
  956.             }
  957.         }
  958.         else if(httpEntity instanceof HttpBaseResponseEntity<?>) {
  959.                
  960.             HttpBaseResponseEntity<?> response = (HttpBaseResponseEntity<?>) httpEntity;
  961.             ApiResponse apiResponseFound = null;
  962.             ApiResponse apiResponseDefault = null;
  963.            
  964.             if(operation.getResponses()!=null) {
  965.                 for (ApiResponse apiResponse : operation.getResponses()) {
  966.                     if(apiResponse.isDefaultHttpReturnCode()) {
  967.                         apiResponseDefault = apiResponse;
  968.                     }
  969.                     if(response.getStatus() == apiResponse.getHttpReturnCode()){
  970.                         apiResponseFound = apiResponse;
  971.                         break;
  972.                     }                                      
  973.                 }
  974.             }
  975.            
  976.             if(apiResponseFound==null && apiResponseDefault!=null) {
  977.                 apiResponseFound = apiResponseDefault;
  978.             }  
  979.             if(apiResponseFound!=null){
  980.                 // eventuali errori di stato non trovato sono gestiti successivavemnte nella validazione
  981.                 bodyParameters = apiResponseFound.getBodyParameters();
  982.             }
  983.                    
  984.         }
  985.         return bodyParameters;
  986.     }
  987.    
  988.     @Override
  989.     public void validatePreConformanceCheck(HttpBaseEntity<?> httpEntity,
  990.             ApiOperation operation, Object... args) throws ProcessingException, ValidatorException {

  991.         List<ApiBodyParameter> bodyParameters = this.getBodyParameters(httpEntity, operation);

  992.         // se e' attivo openApi4j intanto valido subito
  993.         if(this.openApi4j!=null) {
  994.             validateWithOpenApi4j(httpEntity, operation);
  995.         }
  996.         else if(this.swaggerRequestValidator!=null) {
  997.             validateWithSwaggerRequestValidator(httpEntity, operation);
  998.         }
  999.        
  1000.        
  1001.         // Controllo poi i campi required come controllo aggiuntivo a openApi4j
  1002.         boolean required = false;
  1003.         if(bodyParameters!=null && !bodyParameters.isEmpty()) {
  1004.             for(ApiBodyParameter body: bodyParameters) {
  1005.                 if(body.isRequired())
  1006.                     required = true;
  1007.             }
  1008.         }
  1009.         if(required) {
  1010.             if(httpEntity.getContent() == null) {
  1011.                 throw new ValidatorException("Required body undefined");
  1012.             }
  1013.         }
  1014.        
  1015.         // infine se non e' attivo openApi4j effettuo la validazione alternativa
  1016.         if(this.openApi4j==null && this.swaggerRequestValidator==null) {
  1017.             if(bodyParameters!=null && !bodyParameters.isEmpty()) {
  1018.            
  1019.                 try {
  1020.                    
  1021.                     boolean isJson =  httpEntity.getContentType()!=null && httpEntity.getContentType().toLowerCase().contains("json"); // supporta per adesso solo json, la validazione xml non è funzionante
  1022.                     if(isJson) {
  1023.                    
  1024.                         //System.out.println("==================== ("+httpEntity.getClass().getName()+") ====================");
  1025.                         List<IJsonSchemaValidator> validatorLst = getValidatorList(operation, httpEntity);
  1026.                         //System.out.println("SIZE: "+validatorLst.size());
  1027.                         boolean valid = false;
  1028.                         Exception exc = null;
  1029.                         if(httpEntity.getContent()!=null) {
  1030.                             byte[] bytes = httpEntity.getContent().toString().getBytes();
  1031.                             for(IJsonSchemaValidator validator: validatorLst) {
  1032.                                 ValidationResponse response = validator.validate(bytes);
  1033.                                 if(!ESITO.OK.equals(response.getEsito())) {
  1034.                                     exc = response.getException();
  1035.                                 } else {
  1036.                                     valid = true;
  1037.                                 }
  1038.                             }
  1039.                         }
  1040.                         else {
  1041.                             throw new ValidatorException("Content undefined");
  1042.                         }
  1043.                        
  1044.                         if(!valid) {
  1045.                             throw new ValidatorException(exc);
  1046.                         }
  1047.                        
  1048.                     }
  1049.                    
  1050.                 } catch (ValidationException e) {
  1051.                     throw new ValidatorException(e);
  1052.                 }
  1053.             }
  1054.         }

  1055.     }

  1056.     /**
  1057.      * @param operation
  1058.      * @return
  1059.      */
  1060.     private List<IJsonSchemaValidator> getValidatorList(ApiOperation operation, HttpBaseEntity<?> httpEntity) throws ValidatorException {
  1061.         List<IJsonSchemaValidator> lst = new ArrayList<>();
  1062.        
  1063.         if(this.onlySchemas) {
  1064.             if(this.validatorMap!=null) {
  1065.                 lst.addAll(this.validatorMap.values());
  1066.             }
  1067.         }
  1068.         else {
  1069.        
  1070.             List<ApiBodyParameter> bodyParameters = this.getBodyParameters(httpEntity, operation);
  1071.            
  1072.             if(bodyParameters!=null && !bodyParameters.isEmpty()) {
  1073.                 for(ApiBodyParameter body: bodyParameters) {
  1074.                    
  1075.                     String key = null;
  1076.                     if(body.getElement() instanceof ApiReference) {
  1077.                         ApiReference apiRef = (ApiReference) body.getElement();
  1078.                         //System.out.println("API REF ref["+apiRef.getSchemaRef()+"] ["+apiRef.getType()+"]");
  1079.                         key = apiRef.getSchemaRef()+"#"+apiRef.getType();
  1080.                     }
  1081.                     else {
  1082.                         key = body.getElement().toString();
  1083.                     }
  1084.                    
  1085.                     //System.out.println("SEARCH ["+body.getElement().getClass().getName()+"] ["+body.getElement()+"] key["+key+"] ...");
  1086.                    
  1087.                     if(this.validatorMap!=null && this.validatorMap.containsKey(key)) {
  1088.                         //System.out.println("ADD VALIDATORE ["+key+"]: ["+this.validatorMap.get(key)+"]");
  1089.                         lst.add(this.validatorMap.get(key));
  1090.                     }
  1091.                 }
  1092.             }
  1093.            
  1094.         }
  1095.            
  1096.         if(lst.isEmpty())
  1097.             throw new ValidatorException("Validator not found");
  1098.        
  1099.         return lst;
  1100.     }
  1101.    
  1102.     private void validateWithOpenApi4j(HttpBaseEntity<?> httpEntity, ApiOperation operation) throws ProcessingException, ValidatorException {
  1103.                
  1104.         Operation operationOpenApi4j = null;
  1105.         Path pathOpenApi4j = null;
  1106.         for (String path :this.openApi4j.getPaths().keySet()) {
  1107.             Path pathO = this.openApi4j.getPaths().get(path);
  1108.             for (String method : pathO.getOperations().keySet()) {
  1109.                 Operation op = pathO.getOperation(method);
  1110.                 //System.out.println("CHECK: ["+method+"] "+path);
  1111.                 String normalizePath = ApiOperation.normalizePath(path);
  1112.                 if(operation.getHttpMethod().toString().equalsIgnoreCase(method) && operation.getPath().equals(normalizePath)) {
  1113.                     operationOpenApi4j = op;
  1114.                     pathOpenApi4j = pathO;
  1115.                     break;
  1116.                 }
  1117.             }
  1118.         }
  1119.         if(operationOpenApi4j==null || pathOpenApi4j==null) {
  1120.             throw new ProcessingException("Resource "+operation.getHttpMethod()+" "+operation.getPath()+" not found in OpenAPI 3");
  1121.         }
  1122.        
  1123.         try {
  1124.        
  1125.             ValidationData<Void> vData = new ValidationData<>();
  1126.             this.openApi4j.setServers(null); // se lascio la definizione dei server, il validatePath sottostante verifica che la url corrisponda anche con la parte del server
  1127.             OperationValidator val = new OperationValidator(this.openApi4j, pathOpenApi4j, operationOpenApi4j);
  1128.            
  1129.             if(httpEntity instanceof HttpBaseRequestEntity) {
  1130.                
  1131.                 HttpBaseRequestEntity<?> httpRequest = (HttpBaseRequestEntity<?>) httpEntity;
  1132.                 Request requestOpenApi4j = buildRequestOpenApi4j(httpRequest.getUrl(), httpRequest.getMethod().toString(),
  1133.                         httpRequest.getParameters(), httpRequest.getCookies(), httpRequest.getHeaders(),
  1134.                         httpRequest.getContent());
  1135.                 if(this.openApi4jConfig.isValidateRequestPath()) {
  1136.                     val.validatePath(requestOpenApi4j, vData); // LA url fornita deve corrispondere alla parte delle risorse SENZA la parte del server
  1137.                 }
  1138.                 if(this.openApi4jConfig.isValidateRequestQuery()) {
  1139.                     val.validateQuery(requestOpenApi4j, vData);
  1140.                 }
  1141.                 if(this.openApi4jConfig.isValidateRequestHeaders()) {
  1142.                     val.validateHeaders(requestOpenApi4j, vData);
  1143.                 }
  1144.                 if(this.openApi4jConfig.isValidateRequestCookie()) {
  1145.                     val.validateCookies(requestOpenApi4j, vData);
  1146.                 }
  1147.                 if(this.openApi4jConfig.isValidateRequestBody()) {
  1148.                     val.validateBody(requestOpenApi4j, vData);
  1149.                 }
  1150.             }
  1151.             else if(httpEntity instanceof HttpBaseResponseEntity<?>) {
  1152.                    
  1153.                 HttpBaseResponseEntity<?> response = (HttpBaseResponseEntity<?>) httpEntity;
  1154.                 Response responseOpenApi4j = buildResponseOpenApi4j(response.getStatus(), response.getHeaders(),
  1155.                         response.getContent());
  1156.                 if(this.openApi4jConfig.isValidateResponseHeaders()) {
  1157.                     val.validateHeaders(responseOpenApi4j, vData);
  1158.                 }
  1159.                 if(this.openApi4jConfig.isValidateResponseBody()) {
  1160.                     val.validateBody(responseOpenApi4j, vData);
  1161.                 }
  1162.             }
  1163.            
  1164.             if(vData.isValid()==false) {
  1165.                 if(vData.results()!=null) {
  1166.                     throw new ValidatorException(vData.results().toString());
  1167.                 }
  1168.                 else {
  1169.                     throw new ValidatorException("Validation failed");
  1170.                 }
  1171.             }
  1172.            
  1173.         }catch(ValidatorException e) {
  1174.             throw e;
  1175.         }catch(Exception e) {
  1176.             throw new ProcessingException(e.getMessage(),e);
  1177.         }
  1178.     }
  1179.     private Request buildRequestOpenApi4j(String urlInvocazione, String method,
  1180.             Map<String, List<String>> queryParams, List<Cookie> cookies, Map<String, List<String>> headers,
  1181.             Object content) throws ProcessingException {

  1182.         try {
  1183.        
  1184.             // Method e path
  1185.             final DefaultRequest.Builder builder = new DefaultRequest.Builder(
  1186.                     urlInvocazione,
  1187.                     Request.Method.getMethod(method));
  1188.    
  1189.             String queryString = null;
  1190.             if(queryParams!=null && !queryParams.isEmpty()) {
  1191.                 StringBuilder sb = new StringBuilder();
  1192.                 Iterator<String> keys = queryParams.keySet().iterator();
  1193.                 while (keys.hasNext()) {
  1194.                     String key = (String) keys.next();
  1195.                     List<String> values = queryParams.get(key);
  1196.                     try{
  1197.                         key = TransportUtils.urlEncodeParam(key,Charset.UTF_8.getValue());
  1198.                     }catch(Exception e){
  1199.                         if(this.log!=null) {
  1200.                             this.log.error("URLEncode key["+key+"] error: "+e.getMessage(),e);
  1201.                         }
  1202.                         else {
  1203.                             e.printStackTrace(System.out);
  1204.                         }
  1205.                     }
  1206.                    
  1207.                     for (String value : values) {
  1208.                         if(sb.length()>0) {
  1209.                             sb.append("&");
  1210.                         }
  1211.                         try{
  1212.                             value = TransportUtils.urlEncodeParam(value,Charset.UTF_8.getValue());
  1213.                         }catch(Exception e){
  1214.                             if(this.log!=null) {
  1215.                                 this.log.error("URLEncode value["+value+"] error: "+e.getMessage(),e);
  1216.                             }
  1217.                             else {
  1218.                                 e.printStackTrace(System.out);
  1219.                             }
  1220.                         }
  1221.                         sb.append(key);
  1222.                         sb.append("=");
  1223.                         sb.append(value);  
  1224.                     }
  1225.                 }
  1226.                 queryString = sb.toString();
  1227.             }
  1228.            
  1229.             // Query string or body
  1230.             if (HttpRequestMethod.GET.toString().equalsIgnoreCase(method)) {
  1231.                 builder.query(queryString);
  1232.             } else {
  1233.                 if(queryString!=null) {
  1234.                     builder.query(queryString); // senno non vengono validati i query parameters
  1235.                 }
  1236.                 if(content!=null) {
  1237.                     String s = null;
  1238.                     byte[] b = null;
  1239.                     InputStream is = null;
  1240.                     if(content instanceof String) {
  1241.                         s = (String) content;
  1242.                     }
  1243.                     else if(content instanceof byte[]) {
  1244.                         b=(byte[])content;
  1245.                     }
  1246.                     else if(content instanceof InputStream) {
  1247.                         is = (InputStream) content;
  1248.                     }
  1249.                     if(s!=null) {
  1250.                         builder.body(Body.from(s));
  1251.                     }
  1252.                     else if(b!=null) {
  1253.                         try(ByteArrayInputStream bin =new ByteArrayInputStream(b)){
  1254.                             builder.body(Body.from(bin));
  1255.                         }
  1256.                     }
  1257.                     else if(is!=null) {
  1258.                         builder.body(Body.from(is));
  1259.                     }
  1260.                     else {
  1261.                         throw new Exception("Type '"+content.getClass().getName()+"' unsupported");
  1262.                     }
  1263.                 }
  1264.             }
  1265.    
  1266.             // Cookies
  1267.             if (cookies != null) {
  1268.                 for (Cookie cookie : cookies) {
  1269.                     builder.cookie(cookie.getName(), cookie.getValue());
  1270.                 }
  1271.             }
  1272.    
  1273.             // Headers
  1274.             if(headers!=null) {
  1275.                 Iterator<String> headerNames = headers.keySet().iterator();
  1276.                 if (headerNames != null) {
  1277.                     while (headerNames.hasNext()) {
  1278.                         String headerName = headerNames.next();
  1279.                         builder.header(headerName, headers.get(headerName));
  1280.                     }
  1281.                 }
  1282.             }
  1283.    
  1284.             return builder.build();
  1285.            
  1286.         }catch(Exception e) {
  1287.             throw new ProcessingException(e.getMessage(),e);
  1288.         }
  1289.     }
  1290.    
  1291.     private static Response buildResponseOpenApi4j(int status, Map<String, List<String>> headers, Object content) throws ProcessingException {
  1292.        
  1293.         try {
  1294.        
  1295.             // status
  1296.             final DefaultResponse.Builder builder = new DefaultResponse.Builder(status);
  1297.            
  1298.             // body
  1299.             if(content!=null) {
  1300.                 String s = null;
  1301.                 byte[] b = null;
  1302.                 InputStream is = null;
  1303.                 if(content instanceof String) {
  1304.                     s = (String) content;
  1305.                 }
  1306.                 else if(content instanceof byte[]) {
  1307.                     b=(byte[])content;
  1308.                 }
  1309.                 else if(content instanceof InputStream) {
  1310.                     is = (InputStream) content;
  1311.                 }
  1312.                 else if(content instanceof Document) {
  1313.                     b=XMLUtils.getInstance().toByteArray(((Document)content));
  1314.                 }
  1315.                 else if(content instanceof Element) {
  1316.                     b=XMLUtils.getInstance().toByteArray(((Element)content));
  1317.                 }
  1318.                
  1319.                 if(s!=null) {
  1320.                     builder.body(Body.from(s));
  1321.                 }
  1322.                 else if(b!=null) {
  1323.                     try(ByteArrayInputStream bin =new ByteArrayInputStream(b)){
  1324.                         builder.body(Body.from(bin));
  1325.                     }
  1326.                 }
  1327.                 else if(is!=null) {
  1328.                     builder.body(Body.from(is));
  1329.                 }
  1330.                 else {
  1331.                     throw new Exception("Type '"+content.getClass().getName()+"' unsupported");
  1332.                 }
  1333.             }
  1334.            
  1335.             // Headers
  1336.             if(headers!=null) {
  1337.                 Iterator<String> headerNames = headers.keySet().iterator();
  1338.                 if (headerNames != null) {
  1339.                   while (headerNames.hasNext()) {
  1340.                     String headerName = headerNames.next();
  1341.                     builder.header(headerName, headers.get(headerName));
  1342.                   }
  1343.                 }
  1344.             }
  1345.            
  1346.             return builder.build();
  1347.            
  1348.         }catch(Exception e) {
  1349.             throw new ProcessingException(e.getMessage(),e);
  1350.         }
  1351.     }
  1352.    
  1353.    

  1354.     private void validateWithSwaggerRequestValidator(HttpBaseEntity<?> httpEntity, ApiOperation gwOperation) throws ProcessingException, ValidatorException {
  1355.        
  1356.         // IMPROVEMENT: Invece di fare la readOperationsMap, meglio uno switch che fa la getGET, getPOST ecc.. giusta.      
  1357.        
  1358.         // Dentro l'openApiSwagger ho i path col dollaro, nell'oggetto openapi di openspcoop invece
  1359.         // ho il path puliti        
  1360.         Optional<Entry<String, PathItem>> item = this.openApiSwagger
  1361.                 .getPaths()
  1362.                 .entrySet()
  1363.                 .stream()
  1364.                 .filter( pathItem ->
  1365.                         ApiOperation.normalizePath(pathItem.getKey()).equals(gwOperation.getPath()))
  1366.                 .findFirst();
  1367.        
  1368.         if(item.isEmpty()) {
  1369.             throw new ProcessingException(
  1370.                     "Resource " + gwOperation.getHttpMethod() + " " + gwOperation.getPath() + " not found in OpenAPI 3");
  1371.         }
  1372.        
  1373.         HttpMethod method = HttpMethod.valueOf(gwOperation.getHttpMethod().toString());
  1374.        
  1375.         io.swagger.v3.oas.models.Operation swaggerOperation =
  1376.                 item.get().getValue().readOperationsMap().get(method);
  1377.    
  1378.         ApiPath apiPath = new ApiPathImpl(httpEntity.getUrl(), null);
  1379.         NormalisedPath requestPath = new NormalisedPathImpl(httpEntity.getUrl(), null);
  1380.                        
  1381.         com.atlassian.oai.validator.model.ApiOperation swaggerValidatorOperation =
  1382.                 new com.atlassian.oai.validator.model.ApiOperation(apiPath, requestPath, method, swaggerOperation);
  1383.        
  1384.         ValidationReport report;
  1385.        
  1386.        
  1387.        
  1388.         if(httpEntity instanceof HttpBaseRequestEntity) {          
  1389.        
  1390.             HttpBaseRequestEntity<?> request = (HttpBaseRequestEntity<?>) httpEntity;
  1391.             var swaggerRequest = buildSwaggerRequest(request);          
  1392.             report = this.swaggerRequestValidator.validateRequest(swaggerRequest, swaggerValidatorOperation);          
  1393.         }
  1394.         else if(httpEntity instanceof HttpBaseResponseEntity<?>) {              
  1395.             HttpBaseResponseEntity<?> response = (HttpBaseResponseEntity<?>) httpEntity;
  1396.             var swaggerResponse = buildSwaggerResponse(response);
  1397.             report = this.swaggerResponseValidator.validateResponse(swaggerResponse, swaggerValidatorOperation);            
  1398.         } else {
  1399.             throw new ProcessingException("Unknown type for HttpBaseEntity: " + httpEntity.getClass().toString());
  1400.        
  1401.         }
  1402.        
  1403.         if (report.hasErrors()) {
  1404.             String msgReport =  SimpleValidationReportFormat.getInstance().apply(report);      
  1405.             throw new ValidatorException(msgReport);
  1406.         }
  1407.        
  1408.     }
  1409.    



  1410.     @Override
  1411.     public void validatePostConformanceCheck(HttpBaseEntity<?> httpEntity,
  1412.             ApiOperation operation, Object... args) throws ProcessingException,
  1413.     ValidatorException {
  1414.        
  1415.     }

  1416.     @Override
  1417.     public void validateValueAsType(ApiParameterType parameterType, String value, String type, ApiSchemaTypeRestriction typeRestriction)
  1418.             throws ProcessingException, ValidatorException {

  1419.         if(type!=null){
  1420.             type = type.trim();

  1421.             BigDecimal numberValue = null;
  1422.             String stringValue = null;
  1423.            
  1424.             if("string".equalsIgnoreCase(type)){
  1425.                 stringValue = value;
  1426.             }
  1427.             else if("byte".equalsIgnoreCase(type) || "unsignedByte".equalsIgnoreCase(type)){
  1428.                 try{
  1429.                     byte v = Byte.parseByte(value);
  1430.                     numberValue = new BigDecimal(v);
  1431.                 }catch(Throwable e){
  1432.                     throw new ValidatorException(e.getMessage(),e);
  1433.                 }
  1434.             }
  1435.             else if("char".equalsIgnoreCase(type)){
  1436.                 if(value.length()>1){
  1437.                     throw new ValidatorException("More than one character");
  1438.                 }
  1439.                 stringValue = value;
  1440.             }
  1441.             else if("double".equalsIgnoreCase(type) || "decimal".equalsIgnoreCase(type)){
  1442.                 try{
  1443.                     double v = Double.parseDouble(value);
  1444.                     numberValue = BigDecimal.valueOf(v);
  1445.                 }catch(Throwable e){
  1446.                     throw new ValidatorException(e.getMessage(),e);
  1447.                 }
  1448.             }
  1449.             else if("float".equalsIgnoreCase(type)){
  1450.                 try{
  1451.                     float v = Float.parseFloat(value);
  1452.                     numberValue = BigDecimal.valueOf(v);
  1453.                 }catch(Throwable e){
  1454.                     throw new ValidatorException(e.getMessage(),e);
  1455.                 }
  1456.             }
  1457.             else if("int".equalsIgnoreCase(type) || "integer".equalsIgnoreCase(type) ||
  1458.                     "positiveInteger".equalsIgnoreCase(type) || "negativeInteger".equalsIgnoreCase(type) ||
  1459.                     "nonPositiveInteger".equalsIgnoreCase(type) || "nonNegativeInteger".equalsIgnoreCase(type) ||
  1460.                     "unsignedInt".equalsIgnoreCase(type) ||
  1461.                     "int32".equalsIgnoreCase(type)){
  1462.                 try{
  1463.                     int i = Integer.parseInt(value);
  1464.                     if("positiveInteger".equalsIgnoreCase(type)){
  1465.                         if(i<=0){
  1466.                             throw new ValidatorException("Expected a positive value");
  1467.                         }
  1468.                     }
  1469.                     else if("nonNegativeInteger".equalsIgnoreCase(type)){
  1470.                         if(i<0){
  1471.                             throw new ValidatorException("Expected a non negative value");
  1472.                         }
  1473.                     }
  1474.                     else if("negativeInteger".equalsIgnoreCase(type)){
  1475.                         if(i>=0){
  1476.                             throw new ValidatorException("Expected a negative value");
  1477.                         }
  1478.                     }
  1479.                     else if("nonPositiveInteger".equalsIgnoreCase(type)){
  1480.                         if(i>0){
  1481.                             throw new ValidatorException("Expected a non positive value");
  1482.                         }
  1483.                     }
  1484.                     else if("unsignedInt".equalsIgnoreCase(type)){
  1485.                         if(i<0){
  1486.                             throw new ValidatorException("Expected a unsigned value");
  1487.                         }
  1488.                     }
  1489.                     numberValue = BigDecimal.valueOf(i);
  1490.                 }catch(Throwable e){
  1491.                     throw new ValidatorException(e.getMessage(),e);
  1492.                 }
  1493.             }
  1494.             else if("long".equalsIgnoreCase(type) || "unsignedLong".equalsIgnoreCase(type)||
  1495.                     "int64".equalsIgnoreCase(type)){
  1496.                 try{
  1497.                     long l = Long.parseLong(value);
  1498.                     if("unsignedLong".equalsIgnoreCase(type)){
  1499.                         if(l<0){
  1500.                             throw new ValidatorException("Expected a unsigned value");
  1501.                         }
  1502.                     }
  1503.                     numberValue = new BigDecimal(l);
  1504.                 }catch(Throwable e){
  1505.                     throw new ValidatorException(e.getMessage(),e);
  1506.                 }
  1507.             }
  1508.             else if("number".equalsIgnoreCase(type)) {
  1509.                 try{
  1510.                     // Any numbers.
  1511.                     try{
  1512.                         double d = Double.parseDouble(value);
  1513.                         numberValue = BigDecimal.valueOf(d);
  1514.                     }catch(Exception e){
  1515.                         long l = Long.parseLong(value);
  1516.                         numberValue = new BigDecimal(l);
  1517.                     }
  1518.                 }catch(Throwable e){
  1519.                     throw new ValidatorException(e.getMessage(),e);
  1520.                 }
  1521.             }
  1522.             else if("short".equalsIgnoreCase(type) || "unsignedShort".equalsIgnoreCase(type)){
  1523.                 try{
  1524.                     short s = Short.parseShort(value);
  1525.                     if("unsignedShort".equalsIgnoreCase(type)){
  1526.                         if(s<0){
  1527.                             throw new ValidatorException("Expected a unsigned value");
  1528.                         }
  1529.                     }
  1530.                     numberValue = new BigDecimal(s);
  1531.                 }catch(Throwable e){
  1532.                     throw new ValidatorException(e.getMessage(),e);
  1533.                 }
  1534.             }
  1535.             else if("boolean".equalsIgnoreCase(type)){
  1536.                 try{
  1537.                     if(!"true".equals(value) && !"false".equals(value)) {
  1538.                         throw new Exception("Only true/false value expected (found: "+value+"); Note that truthy and falsy values such as \"true\", \"\", 0 or null are not considered boolean values.");
  1539.                     }
  1540.                 }catch(Throwable e){
  1541.                     throw new ValidatorException(e.getMessage(),e);
  1542.                 }
  1543.             }
  1544.             else if("anyURI".equalsIgnoreCase(type)){
  1545.                 try{
  1546.                     new URI(value);
  1547.                 }catch(Throwable e){
  1548.                     throw new ValidatorException(e.getMessage(),e);
  1549.                 }
  1550.             }
  1551.             else if("uuid".equalsIgnoreCase(type)){
  1552.                 try{
  1553.                     UUID.fromString(value);
  1554.                 }catch(Throwable e){
  1555.                     throw new ValidatorException(e.getMessage(),e);
  1556.                 }
  1557.             }
  1558.             else if("date-time".equalsIgnoreCase(type)){
  1559.                 try {
  1560.                     DateUtils.validateDateTimeAsRFC3339Sec56(value);
  1561.                 }catch(Throwable e){
  1562.                     throw new ValidatorException(e.getMessage(),e);
  1563.                 }
  1564.             }
  1565.             else if("date".equalsIgnoreCase(type)){
  1566.                 try {
  1567.                     DateUtils.validateDateAsRFC3339Sec56(value);
  1568.                 }catch(Throwable e){
  1569.                     throw new ValidatorException(e.getMessage(),e);
  1570.                 }
  1571.             }
  1572.             /**else if("time".equalsIgnoreCase(type)){
  1573.                 try {
  1574.                     DateUtils.validateTimeAsRFC3339Sec56(value);
  1575.                 }catch(Throwable e){
  1576.                     throw new ValidatorException(e.getMessage(),e);
  1577.                 }
  1578.             }*/
  1579.            
  1580.             if(typeRestriction!=null) {
  1581.                
  1582.                 if(numberValue!=null) {
  1583.                    
  1584.                     // max
  1585.                     if(typeRestriction.getMaximum()!=null) {
  1586.                         int compare = numberValue.compareTo(typeRestriction.getMaximum());
  1587.                         if(compare<0) {
  1588.                             // numberValue < maximum
  1589.                         }
  1590.                         else if(compare>0) {
  1591.                             // numberValue > maximum
  1592.                             throw new ValidatorException("Value higher than the maximum '"+typeRestriction.getMaximum()+"'");
  1593.                         }
  1594.                         else {
  1595.                             // numberValue == maximum
  1596.                             if(typeRestriction.getExclusiveMaximum()!=null && typeRestriction.getExclusiveMaximum()) {
  1597.                                 throw new ValidatorException("Value equals to the maximum '"+typeRestriction.getMaximum()+"' and exclusive maximum is enabled");
  1598.                             }
  1599.                         }
  1600.                     }
  1601.                    
  1602.                     // min
  1603.                     if(typeRestriction.getMinimum()!=null) {
  1604.                         int compare = numberValue.compareTo(typeRestriction.getMinimum());
  1605.                         if(compare<0) {
  1606.                             // numberValue < minimum
  1607.                             throw new ValidatorException("Value lowest than the minimum '"+typeRestriction.getMinimum()+"'");
  1608.                         }
  1609.                         else if(compare>0) {
  1610.                             // numberValue > minimum
  1611.                         }
  1612.                         else {
  1613.                             // numberValue == minimum
  1614.                             if(typeRestriction.getExclusiveMinimum()!=null && typeRestriction.getExclusiveMinimum()) {
  1615.                                 throw new ValidatorException("Value equals to the minimum '"+typeRestriction.getMinimum()+"' and exclusive minimum is enabled");
  1616.                             }
  1617.                         }
  1618.                     }
  1619.                    
  1620.                     // multipleOf
  1621.                     if(typeRestriction.getMultipleOf()!=null) {
  1622.                         if (numberValue.compareTo(typeRestriction.getMultipleOf()) != 0) {
  1623.                            try{
  1624.                                @SuppressWarnings("unused")
  1625.                                BigDecimal bd = numberValue.divide(typeRestriction.getMultipleOf(), 0, RoundingMode.UNNECESSARY);
  1626.                            }
  1627.                            catch(ArithmeticException e) {
  1628.                                throw new ValidatorException("Value is not multiple of '"+typeRestriction.getMultipleOf()+"'");
  1629.                            }
  1630.                         }
  1631.                     }
  1632.                 }
  1633.                
  1634.                 if(stringValue!=null) {
  1635.                    
  1636.                     // enum
  1637.                     if(typeRestriction.getEnumValues()!=null && !typeRestriction.getEnumValues().isEmpty()) {
  1638.                        
  1639.                         List<String> valoriPresenti = new ArrayList<>();
  1640.                         if(typeRestriction.isArrayParameter()) {
  1641.                             if(ApiParameterType.query.equals(parameterType) || ApiParameterType.form.equals(parameterType)) {
  1642.                                 if(typeRestriction.isStyleQueryForm() || typeRestriction.getStyle()==null) { // form è il default
  1643.                                     if(typeRestriction.isExplodeDisabled()) {
  1644.                                         List<String> l = StringUtil.tokenize(stringValue, ",", false, false);
  1645.                                         if(l!=null && !l.isEmpty()) {
  1646.                                             valoriPresenti.addAll(l);
  1647.                                         }
  1648.                                     }
  1649.                                 }
  1650.                                 else if(typeRestriction.isStyleQuerySpaceDelimited()) {
  1651.                                     if(typeRestriction.isExplodeDisabled()) {
  1652.                                         List<String> l = StringUtil.tokenize(stringValue, Pattern.quote(" "), false, false);
  1653.                                         if(l!=null && !l.isEmpty()) {
  1654.                                             valoriPresenti.addAll(l);
  1655.                                         }
  1656.                                     }
  1657.                                 }
  1658.                                 else if(typeRestriction.isStyleQueryPipeDelimited()) {
  1659.                                     if(typeRestriction.isExplodeDisabled()) {
  1660.                                         List<String> l = StringUtil.tokenize(stringValue, Pattern.quote("|"), false, false);
  1661.                                         if(l!=null && !l.isEmpty()) {
  1662.                                             valoriPresenti.addAll(l);
  1663.                                         }
  1664.                                     }
  1665.                                 }
  1666.                             }
  1667.                             else if(ApiParameterType.header.equals(parameterType)) {
  1668.                                 if(typeRestriction.isStyleHeaderSimple() || typeRestriction.getStyle()==null) { // simple è il default
  1669.                                     List<String> l = StringUtil.tokenize(stringValue, ",", false, false);
  1670.                                     if(l!=null && !l.isEmpty()) {
  1671.                                         valoriPresenti.addAll(l);
  1672.                                     }
  1673.                                 }
  1674.                             }
  1675.                             else if(ApiParameterType.path.equals(parameterType)) {
  1676.                                 if(typeRestriction.isStylePathSimple() || typeRestriction.getStyle()==null) { // simple è il default
  1677.                                     List<String> l = StringUtil.tokenize(stringValue, ",", false, false);
  1678.                                     if(l!=null && !l.isEmpty()) {
  1679.                                         valoriPresenti.addAll(l);
  1680.                                     }
  1681.                                 }
  1682.                                 else if(typeRestriction.isStylePathLabel()) {
  1683.                                     if(stringValue.length()>1) {
  1684.                                         String splitPattern = typeRestriction.isExplodeEnabled() ?  "\\." : ",";
  1685.                                         String [] v = stringValue.substring(1).split(splitPattern);
  1686.                                         if(v!=null && v.length>0) {
  1687.                                             for (String valore : v) {
  1688.                                                 valoriPresenti.add(valore);
  1689.                                             }
  1690.                                         }
  1691.                                     }
  1692.                                 }
  1693.                                 else if(typeRestriction.isStylePathMatrix()) {
  1694.                                     String splitPattern = typeRestriction.isExplodeEnabled() ?  ";" : ",";
  1695.                                     List<String> l = getArrayValues(typeRestriction.isExplodeEnabled(), stringValue, splitPattern);
  1696.                                     if(l!=null && !l.isEmpty()) {
  1697.                                         valoriPresenti.addAll(l);
  1698.                                     }
  1699.                                 }
  1700.                             }
  1701.                         }
  1702.                         if(valoriPresenti.isEmpty()) {
  1703.                             valoriPresenti.add(stringValue);
  1704.                         }
  1705.                        
  1706.                         for (String valorePresente : valoriPresenti) {
  1707.                             boolean found = false;
  1708.                             StringBuilder sbList = new StringBuilder();
  1709.                             for (Object o : typeRestriction.getEnumValues()) {
  1710.                                 if(o!=null) {
  1711.                                     String check = o.toString();
  1712.                                     if(sbList.length()>0) {
  1713.                                         sbList.append(",");
  1714.                                     }
  1715.                                     sbList.append(check);
  1716.                                     if(valorePresente.equals(check)) {
  1717.                                         found = true;
  1718.                                         break;
  1719.                                     }
  1720.                                 }
  1721.                             }
  1722.                             if(!found) {
  1723.                                 throw new ValidatorException("Uncorrect enum value '"+valorePresente+"', expected: '"+sbList.toString()+"'");
  1724.                             }
  1725.                         }
  1726.                     }
  1727.                    
  1728.                     // min length
  1729.                     if(typeRestriction.getMinLength()!=null) {
  1730.                         if(stringValue.length()<typeRestriction.getMinLength().intValue()) {
  1731.                             throw new ValidatorException("Too short, expected min length '"+typeRestriction.getMinLength()+"'");
  1732.                         }
  1733.                     }
  1734.                    
  1735.                     // max length
  1736.                     if(typeRestriction.getMaxLength()!=null) {
  1737.                         if(stringValue.length()>typeRestriction.getMaxLength().intValue()) {
  1738.                             throw new ValidatorException("Too big, expected max length '"+typeRestriction.getMaxLength()+"'");
  1739.                         }
  1740.                     }
  1741.                    
  1742.                     /*
  1743.                      * Note that the regular expression is enclosed in the ^…$ tokens, where ^ means the beginning of the string, and $ means the end of the string.
  1744.                      * Without ^…$, pattern works as a partial match, that is, matches any string that contains the specified regular expression.
  1745.                      * For example, pattern: pet matches pet, petstore and carpet. The ^…$ token forces an exact match.
  1746.                      **/
  1747.                     if(typeRestriction.getPattern()!=null) {
  1748.                         String pattern = typeRestriction.getPattern().trim();
  1749.                         try {
  1750.                             if(pattern.startsWith("^") && pattern.endsWith("$")) {
  1751.                                 if(!RegularExpressionEngine.isMatch(stringValue, pattern)) {
  1752.                                     throw new ValidatorException("Pattern match failed ('"+pattern+"')");
  1753.                                 }
  1754.                             }
  1755.                             else {
  1756.                                 if(!RegularExpressionEngine.isFind(stringValue, pattern)) {
  1757.                                     throw new ValidatorException("Pattern match failed ('"+pattern+"')");
  1758.                                 }
  1759.                             }
  1760.                         }
  1761.                         catch(ValidatorException e) {
  1762.                             throw e;
  1763.                         }
  1764.                         catch(Throwable e) {
  1765.                             throw new ValidatorException("Pattern validation error '"+pattern+"': "+e.getMessage(),e);
  1766.                         }
  1767.                     }
  1768.                 }
  1769.             }
  1770.            
  1771.         }

  1772.         // altri tipi non li valido per ora


  1773.     }

  1774.     private static final Pattern PREFIXED_SEMICOLON_NAME_REGEX = Pattern.compile("(?:;)([^;]+)(?:=)([^;]*)");
  1775.     private List<String> getArrayValues(boolean explode, String rawValue, String splitPattern) {
  1776.        
  1777.         try {
  1778.             Matcher matcher = PREFIXED_SEMICOLON_NAME_REGEX.matcher(rawValue);
  1779.    
  1780.             if (explode) {
  1781.                 List<String> arrayValues = new ArrayList<>();
  1782.                 int index = 0;
  1783.                 int limit = 1000; // per gestire DOS
  1784.                 while (matcher.find() && index<limit) {
  1785.                     arrayValues.add(matcher.group(2));
  1786.                     index++;
  1787.                 }
  1788.                 return arrayValues;
  1789.             } else {
  1790.                 return matcher.matches()
  1791.                         ? Arrays.asList(matcher.group(2).split(splitPattern))
  1792.                                 : null;
  1793.             }
  1794.         }catch(Throwable t) {
  1795.             this.log.error(t.getMessage(), t);
  1796.             return null;
  1797.         }
  1798.     }
  1799.    
  1800.    
  1801.     // ================= SWAGGER REQUEST VALIDATOR GLUE CODE =====================

  1802.     private static Method fromHttpMethod(HttpRequestMethod method) {
  1803.         return Method.valueOf(method.toString());
  1804.     }
  1805.    
  1806.    
  1807.     private static com.atlassian.oai.validator.model.Response buildSwaggerResponse(HttpBaseResponseEntity<?> response) throws ProcessingException {

  1808.         final SimpleResponse.Builder builder =
  1809.                 new SimpleResponse.Builder(response.getStatus());
  1810.        
  1811.         if(response.getHeaders()!=null && !response.getHeaders().isEmpty()) {
  1812.             response.getHeaders().forEach(builder::withHeader);
  1813.         }
  1814.        
  1815.         Object content = response.getContent();
  1816.         if(content instanceof String) {
  1817.             builder.withBody( (String) content);
  1818.         }
  1819.         else if(content instanceof byte[]) {
  1820.             builder.withBody((byte[]) content);
  1821.         }
  1822.         else if(content instanceof InputStream) {
  1823.             builder.withBody((InputStream) content);
  1824.         }
  1825.         else if(content instanceof Document) {
  1826.             try {
  1827.                 builder.withBody(XMLUtils.getInstance().toByteArray(((Document)content)));
  1828.             } catch (Exception e) {
  1829.                 throw new ProcessingException(e.getMessage(),e);
  1830.             }
  1831.         }
  1832.         else if(content instanceof Element) {
  1833.             try {
  1834.                 builder.withBody(XMLUtils.getInstance().toByteArray(((Element)content)));
  1835.             } catch (Exception e) {
  1836.                 throw new ProcessingException(e.getMessage(),e);
  1837.             }
  1838.         }
  1839.         else if (content == null) {
  1840.             // nop
  1841.         } else {
  1842.             throw new ProcessingException("Type '"+content.getClass().getName()+"' unsupported");
  1843.         }
  1844.        
  1845.         return builder.build();
  1846.    
  1847.     }
  1848.    
  1849.     private static com.atlassian.oai.validator.model.Request buildSwaggerRequest(HttpBaseRequestEntity<?> request) throws ProcessingException {
  1850.         Object content = request.getContent();
  1851.         final SimpleRequest.Builder builder =
  1852.                 new SimpleRequest.Builder(fromHttpMethod(request.getMethod()),request.getUrl());
  1853.    
  1854.         // BugFix:
  1855.         // Request Accept header '*; q=.2' is not a valid media type
  1856.        
  1857.         // BugFix2:
  1858.         // Request Accept header '[text/xml]' does not match any defined response types. Must be one of: [text/*, application/*].
  1859.        
  1860.         Map<String, List<String>> hdr = request.getHeaders();
  1861.         if(hdr!=null && !hdr.isEmpty()) {
  1862.             List<String> originalValues = TransportUtils.getValues(hdr, HttpConstants.ACCEPT);
  1863. //          List<String> newList = null;
  1864. //          if(originalValues!=null && !originalValues.isEmpty()) {
  1865. //              newList = new ArrayList<>();
  1866. //              for (String original : originalValues) {
  1867. //                  
  1868. //                  String [] acceptHeaders = null;
  1869. //                  if(original.contains(",")) {
  1870. //                      acceptHeaders = original.split(",");
  1871. //                      for (int i = 0; i < acceptHeaders.length; i++) {
  1872. //                          acceptHeaders[i] = acceptHeaders[i].trim();
  1873. //                      }
  1874. //                  }
  1875. //                  else {
  1876. //                      acceptHeaders = new String [] {original.trim()};
  1877. //                  }
  1878. //                  StringBuilder sbNewList = new StringBuilder();
  1879. //                  for (String hdrCheck : acceptHeaders) {
  1880. //                      if(hdrCheck!=null && org.apache.commons.lang.StringUtils.isNotEmpty(hdrCheck.trim())) {
  1881. //                          if(hdrCheck.contains(";")) {
  1882. //                              String [] tmp = hdrCheck.split(";");
  1883. //                              String media = tmp[0];
  1884. //                              if(media!=null && org.apache.commons.lang.StringUtils.isNotEmpty(media.trim())) {
  1885. //                                  if(sbNewList.length()>0) {
  1886. //                                      sbNewList.append(", ");
  1887. //                                  }
  1888. //                                  String v = media.trim();
  1889. //                                  if(v.equals("*")) {
  1890. //                                      v = "*/*";
  1891. //                                  }
  1892. //                                  sbNewList.append(v);
  1893. //                              }
  1894. //                          }
  1895. //                          else {
  1896. //                              if(sbNewList.length()>0) {
  1897. //                                  sbNewList.append(", ");
  1898. //                              }
  1899. //                              String v = hdrCheck.trim();
  1900. //                              if(v.equals("*")) {
  1901. //                                  v = "*/*";
  1902. //                              }
  1903. //                              sbNewList.append(v);
  1904. //                          }
  1905. //                      }
  1906. //                  }
  1907. //                  if(sbNewList.length()>0) {
  1908. //                      newList.add(sbNewList.toString());
  1909. //                  }
  1910. //              }
  1911. //              TransportUtils.removeRawObject(hdr, HttpConstants.ACCEPT);
  1912. //              if(!newList.isEmpty()) {
  1913. //                  hdr.put(HttpConstants.ACCEPT, newList);
  1914. //              }
  1915. //          }
  1916.             TransportUtils.removeRawObject(hdr, HttpConstants.ACCEPT); // lo rimuovo direttamente e non lo faccio validare per risolvere BugFix2
  1917.            
  1918.             if(!hdr.isEmpty()) {
  1919.                 hdr.forEach(builder::withHeader);
  1920.             }
  1921.            
  1922.             //if(newList!=null) {
  1923.             if(originalValues!=null) {
  1924.                 // ripristino
  1925.                 //TransportUtils.removeRawObject(hdr, HttpConstants.ACCEPT);
  1926.                 hdr.put(HttpConstants.ACCEPT, originalValues);
  1927.             }
  1928.         }
  1929.        
  1930.         if(request.getParameters()!=null && !request.getParameters().isEmpty()) {
  1931.             request.getParameters().forEach(builder::withQueryParam);
  1932.         }
  1933.         if (request.getCookies() != null && !request.getCookies().isEmpty()) {
  1934.             Cookie cookie = request.getCookies().get(0);
  1935.             String cookiesValue = cookie.getName() + HttpConstants.COOKIE_NAME_VALUE_SEPARATOR + cookie.getValue();
  1936.                        
  1937.             for (int i = 1; i < request.getCookies().size(); i++) {
  1938.                 cookie = request.getCookies().get(i);
  1939.                 cookiesValue = cookiesValue + HttpConstants.COOKIE_SEPARATOR+" " + cookie.getName() + HttpConstants.COOKIE_NAME_VALUE_SEPARATOR + cookie.getValue();  
  1940.             }
  1941.             builder.withHeader(HttpConstants.COOKIE, cookiesValue);
  1942.         }
  1943.                            
  1944.         if(content instanceof String) {
  1945.             builder.withBody((String) content);
  1946.         }
  1947.         else if(content instanceof byte[]) {
  1948.             builder.withBody((byte[]) content);
  1949.         }
  1950.         else if(content instanceof InputStream) {
  1951.             builder.withBody( (InputStream) content);
  1952.         }
  1953.         else if(content != null){
  1954.             throw new ProcessingException("Type '"+content.getClass().getName()+"' unsupported");
  1955.         }
  1956.        
  1957.         return builder.build();
  1958.     }
  1959.    
  1960.    
  1961.     /**
  1962.      *
  1963.      *  Questo codice è copiato dall'OpenApiLoader di atlassian, utilizzato perchè il
  1964.      *  resolverfully fa modifiche alla openApi che vanno a interferire con la validazione
  1965.      */
  1966.      // Adding this method to strip off the object type association applied by
  1967.     // io.swagger.v3.parser.util.ResolverFully (ln 410) where the operation sets
  1968.     // type field to "object" if type field is null. This causes issues for anyOf
  1969.     // and oneOf validations.
  1970.    
  1971.     protected static void removeTypeObjectAssociationWithOneOfAndAnyOfModels(final OpenAPI openAPI) {
  1972.         if (openAPI.getComponents() != null) {
  1973.             removeTypeObjectFromEachValue(openAPI.getComponents().getSchemas(), schema -> schema);
  1974.         }
  1975.     }

  1976.     private static <T> void removeTypeObjectFromEachValue(final Map<String, T> map, final Function<T, Object> function) {
  1977.         if (map != null) {
  1978.             map.values().forEach(it -> removeTypeObjectAssociationWithOneOfAndAnyOfFromSchema(function.apply(it)));
  1979.         }
  1980.     }

  1981.     private static void removeTypeObjectAssociationWithOneOfAndAnyOfFromSchema(final Object object) {
  1982.         if (object instanceof ObjectSchema) {
  1983.             removeTypeObjectFromEachValue(((ObjectSchema) object).getProperties(), schema -> schema);
  1984.         } else if (object instanceof ArraySchema) {
  1985.             removeTypeObjectAssociationWithOneOfAndAnyOfFromSchema(((ArraySchema) object).getItems());
  1986.         } else if (object instanceof ComposedSchema) {
  1987.             final ComposedSchema composedSchema = (ComposedSchema) object;
  1988.             composedSchema.setType(null);
  1989.         }
  1990.     }

  1991.     /**
  1992.      * Removes the Base64 pattern on the {@link OpenAPI} model.
  1993.      * <p>
  1994.      * If that pattern would stay on the model all fields of type string / byte would be validated twice. Once
  1995.      * with the {@link com.github.fge.jsonschema.keyword.validator.common.PatternValidator} and once with
  1996.      * the {@link com.atlassian.oai.validator.schema.format.Base64Attribute}.
  1997.      * To improve validation performance and memory footprint the pattern on string / byte fields will be
  1998.      * removed - so the PatternValidator will not be triggered for those kind of fields.
  1999.      *
  2000.      * @param openAPI the {@link OpenAPI} to correct
  2001.      */
  2002.     protected static void removeRegexPatternOnStringsOfFormatByte(final OpenAPI openAPI) {
  2003.         if (openAPI.getPaths() != null) {
  2004.             openAPI.getPaths().values().forEach(pathItem -> {
  2005.                 pathItem.readOperations().forEach(operation -> {
  2006.                     excludeBase64PatternFromEachValue(operation.getResponses(), io.swagger.v3.oas.models.responses.ApiResponse::getContent);
  2007.                     if (operation.getRequestBody() != null) {
  2008.                         excludeBase64PatternFromSchema(operation.getRequestBody().getContent());
  2009.                     }
  2010.                     if (operation.getParameters() != null) {
  2011.                         operation.getParameters().forEach(it -> excludeBase64PatternFromSchema(it.getContent()));
  2012.                         operation.getParameters().forEach(it -> excludeBase64PatternFromSchema(it.getSchema()));
  2013.                     }
  2014.                 });
  2015.             });
  2016.         }
  2017.         if (openAPI.getComponents() != null) {
  2018.             excludeBase64PatternFromEachValue(openAPI.getComponents().getResponses(), io.swagger.v3.oas.models.responses.ApiResponse::getContent);
  2019.             excludeBase64PatternFromEachValue(openAPI.getComponents().getRequestBodies(), RequestBody::getContent);
  2020.             excludeBase64PatternFromEachValue(openAPI.getComponents().getHeaders(), Header::getContent);
  2021.             excludeBase64PatternFromEachValue(openAPI.getComponents().getHeaders(), Header::getSchema);
  2022.             excludeBase64PatternFromEachValue(openAPI.getComponents().getParameters(), Parameter::getContent);
  2023.             excludeBase64PatternFromEachValue(openAPI.getComponents().getParameters(), Parameter::getSchema);
  2024.             excludeBase64PatternFromEachValue(openAPI.getComponents().getSchemas(), schema -> schema);
  2025.         }
  2026.     }

  2027.     private static <T> void excludeBase64PatternFromEachValue(final Map<String, T> map, final Function<T, Object> function) {
  2028.         if (map != null) {
  2029.             map.values().forEach(it -> excludeBase64PatternFromSchema(function.apply(it)));
  2030.         }
  2031.     }

  2032.     private static void excludeBase64PatternFromSchema(final Object object) {
  2033.         if (object instanceof Content) {
  2034.             excludeBase64PatternFromEachValue((Content) object, MediaType::getSchema);
  2035.         } else if (object instanceof ObjectSchema) {
  2036.             excludeBase64PatternFromEachValue(((ObjectSchema) object).getProperties(), schema -> schema);
  2037.         } else if (object instanceof ArraySchema) {
  2038.             excludeBase64PatternFromSchema(((ArraySchema) object).getItems());
  2039.         } else if (object instanceof StringSchema) {
  2040.             final StringSchema stringSchema = (StringSchema) object;
  2041.             // remove the pattern _only_ if it's a String / Byte field
  2042.             if ("byte".equals(stringSchema.getFormat())) {
  2043.                 stringSchema.setPattern(null);
  2044.             }
  2045.         }
  2046.     }
  2047.    
  2048. }