SwaggerRequestValidatorOpenAPI.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.IOException;
  22. import java.io.Serializable;
  23. import java.util.Arrays;
  24. import java.util.HashMap;
  25. import java.util.Map;

  26. import org.openspcoop2.utils.SemaphoreLock;
  27. import org.openspcoop2.utils.openapi.validator.swagger.SwaggerValidatorUtils;
  28. import org.openspcoop2.utils.rest.ProcessingException;
  29. import org.openspcoop2.utils.rest.api.Api;
  30. import org.openspcoop2.utils.rest.api.ApiSchema;
  31. import org.openspcoop2.utils.rest.api.ApiSchemaType;

  32. import com.fasterxml.jackson.databind.JsonNode;

  33. import io.swagger.models.Swagger;
  34. import io.swagger.parser.Swagger20Parser;
  35. import io.swagger.parser.util.SwaggerDeserializationResult;
  36. import io.swagger.v3.oas.models.OpenAPI;
  37. import io.swagger.v3.parser.OpenAPIResolver;
  38. import io.swagger.v3.parser.OpenAPIV3Parser;
  39. import io.swagger.v3.parser.converter.SwaggerConverter;
  40. import io.swagger.v3.parser.core.models.SwaggerParseResult;
  41. import io.swagger.v3.parser.util.ResolverFully;

  42. /**
  43.  * SwaggerRequestValidatorAPI
  44.  *
  45.  *
  46.  * @author Poli Andrea (apoli@link.it)
  47.  * @author $Author$
  48.  * @version $Rev$, $Date$
  49.  */
  50. public class SwaggerRequestValidatorOpenAPI implements Serializable {

  51.     private static final long serialVersionUID = 1L;
  52.    
  53.     private JsonNode schemaNodeRoot;
  54.     private OpenapiLibraryValidatorConfig openApi4jConfig;
  55.     private Api api;
  56.    
  57.     public SwaggerRequestValidatorOpenAPI(JsonNode schemaNodeRoot, OpenapiLibraryValidatorConfig openApi4jConfig, Api api) {
  58.         this.schemaNodeRoot = schemaNodeRoot;
  59.         this.openApi4jConfig = openApi4jConfig;
  60.         this.api = api;
  61.     }
  62.    
  63.     private transient OpenAPI openApiSwagger;
  64.    
  65.     public OpenAPI getOpenApiSwagger() throws ProcessingException, IOException {
  66.         if(this.openApiSwagger==null) {
  67.             init();
  68.         }
  69.         if(this.openApiSwagger==null) {
  70.             throw new ProcessingException("OpenAPI init failed");
  71.         }
  72.         return this.openApiSwagger;
  73.     }

  74.     private transient org.openspcoop2.utils.Semaphore semaphore = new org.openspcoop2.utils.Semaphore("SwaggerRequestValidatorOpenAPI");
  75.     public void init() throws ProcessingException, IOException {
  76.         if(this.openApiSwagger!=null) {
  77.             return;
  78.         }
  79.         SemaphoreLock lock = this.semaphore.acquireThrowRuntime("init");
  80.         try {
  81.             // Parsing
  82.             SwaggerParseResult result;
  83.             String version = SwaggerValidatorUtils.getSchemaVersion(this.schemaNodeRoot);
  84.             if (SwaggerValidatorUtils.isSchemaV2(version)) {
  85.                 Swagger20Parser swaggerParser = new Swagger20Parser();
  86.                 SwaggerConverter swaggerConverter = new SwaggerConverter();
  87.                 Swagger swagger = swaggerParser.read(this.schemaNodeRoot);
  88.                
  89.                 if (swagger != null) {
  90.                     SwaggerDeserializationResult foo = new SwaggerDeserializationResult();
  91.                     foo.setMessages(Arrays.asList());
  92.                     foo.setSwagger(swagger);
  93.                     result = swaggerConverter.convert(foo);
  94.                 } else {
  95.                     throw new ProcessingException("Unknown error while parsing the Swagger root node.");                                
  96.                 }
  97.                
  98.             } else {        
  99.                 OpenAPIV3Parser v3Parser = new OpenAPIV3Parser();
  100.                 result = v3Parser.parseJsonNode(null, this.schemaNodeRoot);
  101.             }
  102.             if (result.getOpenAPI() == null) {
  103.                 throw new ProcessingException("Error while parsing the OpenAPI root node: " + String.join("\n", result.getMessages()));
  104.             }
  105.            
  106.             // Se l'api non è stata mergiata, recuperiamo gli schemi dei riferimenti esterni
  107.            
  108.             Map<String,String> schemaMapSerialized = new HashMap<>();
  109.             if (!this.openApi4jConfig.isMergeAPISpec() && this.api.getSchemas()!=null) {                            
  110.                 for (ApiSchema apiSchema : this.api.getSchemas()) {
  111.                     if(ApiSchemaType.JSON.equals(apiSchema.getType()) || ApiSchemaType.YAML.equals(apiSchema.getType())) {
  112.                         String schemaBytes = new String(apiSchema.getContent());
  113.                         schemaMapSerialized.put(apiSchema.getName(), schemaBytes);
  114.                         schemaMapSerialized.put("./"+apiSchema.getName(), schemaBytes);
  115.                     }
  116.                 }
  117.             }
  118.             OpenAPIResolver v3Resolver = new OpenAPIResolver(result.getOpenAPI(), schemaMapSerialized, null, 0);
  119.             result.setOpenAPI(v3Resolver.resolve());
  120.             if (!this.openApi4jConfig.isSwaggerRequestValidator_ResolveFullyApiSpec()) {
  121.                
  122.                 // Passo false per non risolvere i combinators, poichè quando vengono risolti non c'è modo
  123.                 // di ricordarsi i singoli attributi degli schemi combinati (oneOf, allOf ecc..)
  124.                 ResolverFully v3ResolverFully = new ResolverFully(false);
  125.                 v3ResolverFully.resolveFully(result.getOpenAPI());
  126.             }
  127.    
  128.             // Pulisco la openApi con le utility dell' OpenApiLoader di atlassian
  129.             Validator.removeRegexPatternOnStringsOfFormatByte(result.getOpenAPI());
  130.             Validator.removeTypeObjectAssociationWithOneOfAndAnyOfModels(result.getOpenAPI());
  131.            
  132.             // Validazione semantica se richiesta
  133.    
  134.             if(this.openApi4jConfig.isValidateAPISpec()) {
  135.                 if (result.getMessages().size() != 0) {
  136.                     throw new ProcessingException(
  137.                             "OpenAPI3 not valid: " + String.join("\n", result.getMessages())
  138.                             );
  139.                 }
  140.             }
  141.            
  142.             this.openApiSwagger = result.getOpenAPI();
  143.            
  144.         }finally {
  145.             this.semaphore.release(lock, "init");
  146.         }
  147.     }
  148.    
  149. }