FGEJsonschemaValidator.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.json.validation;

  21. import java.io.ByteArrayOutputStream;
  22. import java.util.Iterator;

  23. import org.openspcoop2.utils.LoggerWrapperFactory;
  24. import org.openspcoop2.utils.json.IJsonSchemaValidator;
  25. import org.openspcoop2.utils.json.JSONUtils;
  26. import org.openspcoop2.utils.json.JsonSchemaValidatorConfig;
  27. import org.openspcoop2.utils.json.ValidationException;
  28. import org.openspcoop2.utils.json.ValidationResponse;
  29. import org.openspcoop2.utils.json.ValidationResponse.ESITO;
  30. import org.slf4j.Logger;

  31. import com.fasterxml.jackson.databind.JsonNode;
  32. import com.fasterxml.jackson.databind.ObjectMapper;
  33. import com.github.fge.jsonschema.core.report.LogLevel;
  34. import com.github.fge.jsonschema.core.report.ProcessingMessage;
  35. import com.github.fge.jsonschema.core.report.ProcessingReport;
  36. import com.github.fge.jsonschema.main.JsonSchemaFactory;
  37. import com.github.fge.jsonschema.main.JsonValidator;

  38. /**
  39.  * FGEJsonschemaValidator
  40.  *
  41.  * @author Giovanni Bussu (bussu@link.it)
  42.  * @author $Author$
  43.  * @version $Rev$, $Date$
  44.  */
  45. public class FGEJsonschemaValidator implements IJsonSchemaValidator {

  46.     private JsonValidator validator;
  47.     private JsonNode schema;
  48.     private byte[] schemaBytes;
  49.    
  50.     private ObjectMapper jsonMapper;

  51.     private Logger log;
  52.     private boolean logError;
  53.    
  54.     public FGEJsonschemaValidator() {
  55.         this.validator = JsonSchemaFactory.byDefault().getValidator();
  56.         this.jsonMapper = new ObjectMapper();
  57.        
  58.     }

  59.     @Override
  60.     public void setSchema(byte[] schema, JsonSchemaValidatorConfig config, Logger log) throws ValidationException {
  61.        
  62.         this.log = log;
  63.         if(this.log==null) {
  64.             this.log = LoggerWrapperFactory.getLogger(FGEJsonschemaValidator.class);
  65.         }
  66.         this.logError = config!=null ? config.isEmitLogError() : true;
  67.         this.schemaBytes = schema;
  68.        
  69.         try {
  70.             this.schema = this.jsonMapper.readTree(schema);

  71.             if(config!=null) {
  72.                 switch(config.getAdditionalProperties()) {
  73.                 case DEFAULT:
  74.                     break;
  75.                 case FORCE_DISABLE: ValidationUtils.disableAdditionalProperties(this.jsonMapper, this.schema, true, true);
  76.                     break;
  77.                 case FORCE_STRING: ValidationUtils.disableAdditionalProperties(this.jsonMapper, this.schema, false, true);
  78.                     break;
  79.                 case IF_NULL_DISABLE: ValidationUtils.disableAdditionalProperties(this.jsonMapper, this.schema, true, false);
  80.                     break;
  81.                 case IF_NULL_STRING: ValidationUtils.disableAdditionalProperties(this.jsonMapper, this.schema, false, false);
  82.                     break;
  83.                 default:
  84.                     break;
  85.                 }
  86.             }
  87.            
  88.             if(config!=null) {
  89.                 switch(config.getPoliticaInclusioneTipi()) {
  90.                 case DEFAULT:
  91.                     break;
  92.                 case ALL: ValidationUtils.addTypes(this.jsonMapper, this.schema, config.getTipi(), true);
  93.                     break;
  94.                 case ANY: ValidationUtils.addTypes(this.jsonMapper, this.schema, config.getTipi(), false);
  95.                     break;
  96.                 default:
  97.                     break;
  98.                 }
  99.             }
  100.            
  101.             if(config!=null && config.isVerbose()) {
  102.                 try {
  103.                     ByteArrayOutputStream bout = new ByteArrayOutputStream();
  104.                     JSONUtils.getInstance(true).writeTo(this.schema, bout);
  105.                     bout.flush();
  106.                     bout.close();
  107.                     this.log.debug("JSON Schema: "+bout.toString());
  108.                 }catch(Exception e) {
  109.                     this.log.debug("JSON Schema build error: "+e.getMessage(),e);
  110.                 }
  111.             }
  112.            

  113.         } catch(Exception e) {
  114.             throw new ValidationException(e);
  115.         }
  116.     }

  117.     @Override
  118.     public ValidationResponse validate(byte[] rawObject) throws ValidationException {

  119.         ValidationResponse response = new ValidationResponse();
  120.         try {
  121.             boolean expectedString = false;
  122.             if(this.schema.has("type")) {
  123.                 try {
  124.                     JsonNode type = this.schema.get("type");
  125.                     String vType = type.asText();
  126.                     expectedString = "string".equals(vType);
  127.                 }catch(Exception e) {}
  128.             }
  129.            
  130.             JsonNode object = null;
  131.             try {
  132.                 if(expectedString) {
  133.                     object = this.jsonMapper.getNodeFactory().textNode(new String(rawObject));
  134.                 }
  135.                 else {
  136.                     object = this.jsonMapper.readTree(rawObject);
  137.                 }
  138.             }
  139.             catch(Exception e) {
  140.                 this.log.error(e.getMessage(),e);
  141.                 String messageString = "Read rawObject as jsonNode failed: "+e.getMessage();
  142.                 response.setEsito(ESITO.KO);
  143.                 if(this.logError) {
  144.                     ValidationUtils.logError(this.log, messageString.toString(), rawObject, this.schemaBytes, this.schema);
  145.                 }
  146.                 response.setException(new Exception(messageString.toString()));
  147.             }
  148.            
  149.             if(object!=null) {
  150.                 ProcessingReport report = this.validator.validate(this.schema, object, true);
  151.                 if(report.isSuccess()) {
  152.                     response.setEsito(ESITO.OK);
  153.                 } else {
  154.                     response.setEsito(ESITO.KO);
  155.                     Iterator<ProcessingMessage> iterator = report.iterator();
  156.                     while(iterator.hasNext()) {
  157.                        
  158.                         ProcessingMessage msg = iterator.next();
  159.                         StringBuilder messageString = new StringBuilder();
  160.                         if(msg.getLogLevel().equals(LogLevel.ERROR) || msg.getLogLevel().equals(LogLevel.FATAL)) {
  161.                             response.getErrors().add(msg.getMessage());
  162.                             messageString.append(msg.getMessage()).append("\n");
  163.                         }
  164.                         if(this.logError) {
  165.                             ValidationUtils.logError(this.log, messageString.toString(), rawObject, this.schemaBytes, this.schema);
  166.                         }
  167.                         response.setException(new Exception(messageString.toString()));
  168.                     }
  169.                 }
  170.             }
  171.         } catch(Exception e) {
  172.             throw new ValidationException(e);
  173.         }
  174.        
  175.         return response;
  176.     }
  177. }