SwaggerOpenApiValidator.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.swagger;

  21. import java.io.BufferedReader;
  22. import java.io.InputStream;
  23. import java.io.InputStreamReader;
  24. import java.util.Optional;
  25. import java.util.stream.Collectors;

  26. import com.fasterxml.jackson.databind.JsonNode;
  27. import com.fasterxml.jackson.databind.ObjectMapper;
  28. import com.fasterxml.jackson.databind.node.ObjectNode;
  29. import com.github.fge.jsonschema.core.exceptions.ProcessingException;
  30. import com.github.fge.jsonschema.core.report.ListProcessingReport;
  31. import com.github.fge.jsonschema.core.report.ListReportProvider;
  32. import com.github.fge.jsonschema.core.report.LogLevel;
  33. import com.github.fge.jsonschema.core.report.ProcessingMessage;
  34. import com.github.fge.jsonschema.core.report.ProcessingReport;
  35. import com.github.fge.jsonschema.main.JsonSchema;
  36. import com.github.fge.jsonschema.main.JsonSchemaFactory;

  37. import io.swagger.util.Json;

  38. /**
  39.  * SwaggerOpenApiValidator
  40.  *
  41.  * @author $Author$
  42.  * @version $Rev$, $Date$
  43.  *
  44.  */
  45. public class SwaggerOpenApiValidator {

  46.     // vedi io.swagger.handler.ValidatorController
  47.    
  48.     private static final String SCHEMA_OPENAPI3_FILE = "schema-openapi3.json";
  49.     private static final String SCHEMA_SWAGGER2_FILE = "schema-swagger-v2.json";
  50.     private static final String INVALID_VERSION = "Unsupported Swagger version";
  51.     static ObjectMapper JsonMapper = Json.mapper();

  52.     private JsonSchema schemaV2;
  53.     private JsonSchema schemaV3;

  54.     public SwaggerOpenApiValidator() {
  55.         String prefix = "/org/openspcoop2/utils/openapi/validator/swagger/";
  56.        
  57.         /*
  58.          * Schemi presi da:
  59.          * - https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/schemas/v3.0/schema.json
  60.          * - https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/schemas/v2.0/schema.json
  61.          *
  62.          * NOTA: lo schema v3 รจ stato modificato per sostituire tutte le occorrenze di
  63.          *          "format": "uri-reference"
  64.          *       con
  65.          *          "format": "uri"
  66.          *       Il validatore non supportava uri-reference
  67.          */    
  68.         this.schemaV2 = resolveJsonSchema(getResourceFileAsString(prefix + SCHEMA_SWAGGER2_FILE), true);
  69.         this.schemaV3 = resolveJsonSchema(getResourceFileAsString(prefix + SCHEMA_OPENAPI3_FILE), true);
  70.     }

  71.     public Optional<String> validate(JsonNode spec) throws ProcessingException {
  72.        
  73.         // Gli swaggerV2 vengono convertiti in OpenAPI, per cui la validazione devo farla prima
  74.         // di aver convertito lo schema del json node nell'oggetto OpenAPI altrimenti si perdono le info
  75.        
  76.         boolean isVersion2 = false;
  77.        
  78.         String version = SwaggerValidatorUtils.getSchemaVersion(spec);
  79.         if (SwaggerValidatorUtils.isSchemaV1(version)) {
  80.             return Optional.of(INVALID_VERSION);            
  81.         } else if (SwaggerValidatorUtils.isSchemaV2(version)) {
  82.             isVersion2 = true;
  83.         } else if (version == null || SwaggerValidatorUtils.isSchemaV3(version)) {
  84.             // siamo in v3
  85.         }
  86.        
  87.         JsonSchema schema = getSchema(isVersion2);
  88.         ProcessingReport report = schema.validateUnchecked(spec);
  89.         ListProcessingReport lp = new ListProcessingReport();
  90.         lp.mergeWith(report);

  91.         StringBuilder result = new StringBuilder("");
  92.         java.util.Iterator<ProcessingMessage> it = lp.iterator();
  93.         while (it.hasNext()) {
  94.             ProcessingMessage pm = it.next();
  95.             result.append(pm.toString());
  96.             result.append("\n");
  97.         }      

  98.         return result.length() == 0 ? Optional.empty() : Optional.of(result.toString());
  99.     }
  100.    
  101.    
  102.     private JsonSchema getSchema(boolean isVersion2) {
  103.         if (isVersion2) {
  104.             return this.schemaV2;
  105.         } else {
  106.             return this.schemaV3;
  107.         }
  108.     }

  109.    
  110.     private JsonSchema resolveJsonSchema(String schemaAsString, boolean removeId) {
  111.         try {
  112.             JsonNode schemaObject = JsonMapper.readTree(schemaAsString);
  113.             if (removeId) {
  114.                 ObjectNode oNode = (ObjectNode) schemaObject;
  115.                 if (oNode.get("id") != null) {
  116.                     oNode.remove("id");
  117.                 }
  118.                 if (oNode.get("$schema") != null) {
  119.                     oNode.remove("$schema");
  120.                 }
  121.                 if (oNode.get("description") != null) {
  122.                     oNode.remove("description");
  123.                 }
  124.             }
  125.            
  126.             // Come schema factory utilizzo quella di atlassian che estende il jsonSchema
  127.             // con altri tipi
  128.             //JsonSchemaFactory factory = SwaggerV20Library.schemaFactory();//JsonSchemaFactory.byDefault();
  129.             JsonSchemaFactory factory = JsonSchemaFactory
  130.                     .newBuilder()
  131.                        .setReportProvider(
  132.                                 // Only emit ERROR and above from the JSON schema validation
  133.                                 new ListReportProvider(LogLevel.WARNING, LogLevel.FATAL))
  134.                     .freeze();
  135.            
  136.             return factory.getJsonSchema(schemaObject);
  137.         } catch (Exception e) {
  138.             throw new RuntimeException("Errore inatteso durante il parsing JSON dello schema: " + e.getMessage());
  139.         }
  140.     }

  141.    
  142.     public String getResourceFileAsString(String fileName) {
  143.        
  144.         try {
  145.             InputStream is = SwaggerOpenApiValidator.class.getResourceAsStream(fileName);
  146.             if (is != null) {
  147.                 BufferedReader reader = new BufferedReader(new InputStreamReader(is));
  148.                 var ret = reader.lines().collect(Collectors.joining(System.lineSeparator()));
  149.                 reader.close();
  150.                 return ret;
  151.             }
  152.         } catch (Exception e) {
  153.             throw new RuntimeException("Errore inatteso durante la lettura del file dello schema: " + e.getMessage());
  154.         }
  155.         return null;
  156.     }

  157. }