Validator.java
- /*
- * GovWay - A customizable API Gateway
- * https://govway.org
- *
- * Copyright (c) 2005-2025 Link.it srl (https://link.it).
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3, as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
- package org.openspcoop2.utils.wadl.validator;
- import java.io.InputStream;
- import java.net.URI;
- import java.util.ArrayList;
- import java.util.List;
- import javax.ws.rs.core.MultivaluedMap;
- import javax.xml.validation.Schema;
- import org.jvnet.ws.wadl.ast.AbstractNode;
- import org.jvnet.ws.wadl.ast.FaultNode;
- import org.jvnet.ws.wadl.ast.MethodNode;
- import org.jvnet.ws.wadl.ast.RepresentationNode;
- import org.jvnet.ws.wadl.ast.ResourceNode;
- import org.openspcoop2.utils.rest.AbstractApiValidator;
- import org.openspcoop2.utils.rest.ApiParameterType;
- import org.openspcoop2.utils.rest.ApiValidatorConfig;
- import org.openspcoop2.utils.rest.IApiValidator;
- import org.openspcoop2.utils.rest.ProcessingException;
- import org.openspcoop2.utils.rest.ValidatorException;
- import org.openspcoop2.utils.rest.api.Api;
- import org.openspcoop2.utils.rest.api.ApiOperation;
- import org.openspcoop2.utils.rest.api.ApiSchemaTypeRestriction;
- import org.openspcoop2.utils.rest.entity.HttpBaseEntity;
- import org.openspcoop2.utils.rest.entity.HttpBaseRequestEntity;
- import org.openspcoop2.utils.rest.entity.HttpBaseResponseEntity;
- import org.openspcoop2.utils.wadl.ApplicationWrapper;
- import org.openspcoop2.utils.wadl.WADLApi;
- import org.openspcoop2.utils.wadl.WADLException;
- import org.openspcoop2.utils.wadl.WADLUtilities;
- import org.openspcoop2.utils.xml.AbstractValidatoreXSD;
- import org.openspcoop2.utils.xml.AbstractXMLUtils;
- import org.openspcoop2.utils.xml.ValidatoreXSD;
- import org.slf4j.Logger;
- import org.w3c.dom.Document;
- import org.w3c.dom.Element;
- import org.w3c.dom.Node;
- /**
- * Validator
- *
- *
- * @author Poli Andrea (apoli@link.it)
- * @author $Author$
- * @version $Rev$, $Date$
- */
- public class Validator extends AbstractApiValidator implements IApiValidator {
- private WADLApi wadlApi;
- private ApplicationWrapper application;
- private Logger log;
- private AbstractXMLUtils xmlUtils;
- private Schema schema;
- private boolean initialize = false;
-
-
- @Override
- public void init(Logger log, Api api, ApiValidatorConfig config) throws WADLException {
- try{
- this.wadlApi = (WADLApi) api;
- this.log = log;
- this.application = this.wadlApi.getApplicationWadlWrapper();
- this.xmlUtils = config.getXmlUtils();
-
- // Costruisco l'eventuale schema XSD necessario per una validazione rispetto a schemi XSD
- if(this.application.getResources().size()>0){
- this.schema = this.application.buildSchemaCollection(this.log).buildSchema(this.log);
- }
-
- this.initialize = true;
- }catch(Exception e){
- throw new WADLException(e.getMessage(),e);
- }
- }
-
- public Validator(){}
-
- @Override
- public void close(Logger log, Api api, ApiValidatorConfig config) throws ProcessingException{
-
- }
-
- @Override
- public void validate(HttpBaseEntity<?> httpEntity) throws ProcessingException, ValidatorException{
-
- if(!this.initialize){
- throw new WADLException("Validatore non inizializzato");
- }
- List<Object> context = new ArrayList<>();
-
- this.validate(this.wadlApi, httpEntity, context);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public void validatePreConformanceCheck(HttpBaseEntity<?> httpEntity,ApiOperation operation,Object ... args) throws ProcessingException,ValidatorException{
-
- // Effettuo la validazione del contenuto
-
- // Recupera il resource node corrispondente alla url
- ResourceNode resourceNode = WADLUtilities.findResourceNode(this.application.getApplicationNode(),httpEntity.getUrl());
-
- // Recupera il metodo corrispondente al method invocato
- MethodNode methodNode = WADLUtilities.findMethodNode(resourceNode,httpEntity.getMethod());
-
- // Aggiungo in context
- ((List<Object>)args[0]).add(resourceNode);
- ((List<Object>)args[0]).add(methodNode);
-
- this.validateAgainstXSDSchema(httpEntity, resourceNode, methodNode);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public void validatePostConformanceCheck(HttpBaseEntity<?> httpEntity,ApiOperation operation,Object ... args) throws ProcessingException,ValidatorException{
-
- // Verifico che un eventuale contenuto che rispetta lo schema, sia esattamente anche quello atteso per l'operazione
-
- ResourceNode resourceNode = (ResourceNode) ((List<Object>)args[0]).get(0);
- MethodNode methodNode = (MethodNode) ((List<Object>)args[0]).get(1);
-
- this.wadlConformanceCheck(httpEntity, resourceNode, methodNode);
- }
-
- @Override
- public void validateValueAsType(ApiParameterType parameterType, String value,String type, ApiSchemaTypeRestriction typeRestriction) throws ProcessingException,ValidatorException{
-
- // Tipi XSD : {http://www.w3.org/2001/XMLSchema}string
- if(type.startsWith("{http://www.w3.org/2001/XMLSchema}")){
- String tipoEffettivo = type.substring("{http://www.w3.org/2001/XMLSchema}".length());
- if(tipoEffettivo!=null){
- tipoEffettivo = tipoEffettivo.trim();
-
- if("byte".equalsIgnoreCase(tipoEffettivo) || "unsignedByte".equalsIgnoreCase(tipoEffettivo)){
- try{
- Byte.parseByte(value);
- }catch(Exception e){
- throw new ValidatorException(e.getMessage(),e);
- }
- }
- else if("char".equalsIgnoreCase(tipoEffettivo)){
- if(value.length()>1){
- throw new ValidatorException("More than one character");
- }
- }
- else if("double".equalsIgnoreCase(tipoEffettivo) || "decimal".equalsIgnoreCase(tipoEffettivo)){
- try{
- Double.parseDouble(value);
- }catch(Exception e){
- throw new ValidatorException(e.getMessage(),e);
- }
- }
- else if("float".equalsIgnoreCase(tipoEffettivo)){
- try{
- Float.parseFloat(value);
- }catch(Exception e){
- throw new ValidatorException(e.getMessage(),e);
- }
- }
- else if("int".equalsIgnoreCase(tipoEffettivo) || "integer".equalsIgnoreCase(tipoEffettivo) ||
- "positiveInteger".equalsIgnoreCase(tipoEffettivo) || "negativeInteger".equalsIgnoreCase(tipoEffettivo) ||
- "nonPositiveInteger".equalsIgnoreCase(tipoEffettivo) || "nonNegativeInteger".equalsIgnoreCase(tipoEffettivo) ||
- "unsignedInt".equalsIgnoreCase(tipoEffettivo)){
- try{
- int i = Integer.parseInt(value);
- if("positiveInteger".equalsIgnoreCase(tipoEffettivo)){
- if(i<=0){
- throw new ValidatorException("Expected a positive value");
- }
- }
- else if("nonNegativeInteger".equalsIgnoreCase(tipoEffettivo)){
- if(i<0){
- throw new ValidatorException("Expected a non negative value");
- }
- }
- else if("negativeInteger".equalsIgnoreCase(tipoEffettivo)){
- if(i>=0){
- throw new ValidatorException("Expected a negative value");
- }
- }
- else if("nonPositiveInteger".equalsIgnoreCase(tipoEffettivo)){
- if(i>0){
- throw new ValidatorException("Expected a non positive value");
- }
- }
- else if("unsignedInt".equalsIgnoreCase(tipoEffettivo)){
- if(i<0){
- throw new ValidatorException("Expected a unsigned value");
- }
- }
- }catch(Exception e){
- throw new ValidatorException(e.getMessage(),e);
- }
- }
- else if("long".equalsIgnoreCase(tipoEffettivo) || "unsignedLong".equalsIgnoreCase(tipoEffettivo)){
- try{
- long l = Long.parseLong(value);
- if("unsignedLong".equalsIgnoreCase(tipoEffettivo)){
- if(l<0){
- throw new ValidatorException("Expected a unsigned value");
- }
- }
- }catch(Exception e){
- throw new ValidatorException(e.getMessage(),e);
- }
- }
- else if("short".equalsIgnoreCase(tipoEffettivo) || "unsignedShort".equalsIgnoreCase(tipoEffettivo)){
- try{
- short s = Short.parseShort(value);
- if("unsignedShort".equalsIgnoreCase(tipoEffettivo)){
- if(s<0){
- throw new ValidatorException("Expected a unsigned value");
- }
- }
- }catch(Exception e){
- throw new ValidatorException(e.getMessage(),e);
- }
- }
- else if("boolean".equalsIgnoreCase(tipoEffettivo)){
- try{
- Boolean.parseBoolean(value);
- }catch(Exception e){
- throw new ValidatorException(e.getMessage(),e);
- }
- }
- else if("anyURI".equalsIgnoreCase(tipoEffettivo)){
- try{
- new URI(value);
- }catch(Exception e){
- throw new ValidatorException(e.getMessage(),e);
- }
- }
- }
-
- }
-
- // altri tipi non li valido per ora
-
- }
-
-
-
- private void validateAgainstXSDSchema(HttpBaseEntity<?> httpEntity,ResourceNode resourceNode,MethodNode methodNode) throws WADLException,WADLValidatorException{
- if(this.schema!=null){
-
- try{
-
- AbstractValidatoreXSD validatore = null;
- try{
- validatore = new ValidatoreXSD(this.schema);
-
- }catch(Exception e){
- throw new WADLException("Riscontrato errore durante la costruzione del validatore XSD per il contenuto applicativo: "+e.getMessage(),e);
- }
-
- javax.xml.namespace.QName elementAtteso = null;
-
- AbstractNode nodeXML = getNode(httpEntity, methodNode);
-
- if(nodeXML != null) {
- if(nodeXML instanceof RepresentationNode) {
- elementAtteso = ((RepresentationNode)nodeXML).getElement();
- } else if(nodeXML instanceof FaultNode) {
- elementAtteso = ((FaultNode)nodeXML).getElement();
- }
- }
-
- if(elementAtteso!=null){
- // Devo effettivamente effettuare la validazione XSD
-
- Node node = this.readNode(elementAtteso, httpEntity);
-
- String nomeElemento = null;
- try{
- nomeElemento = node.getLocalName();
- validatore.valida(node,true);
- }catch(Exception e){
- StringBuilder errorMsgValidazioneXSD = new StringBuilder();
- errorMsgValidazioneXSD.append("validation failed");
- errorMsgValidazioneXSD.append(" (element "+nomeElemento+"): "+e.getMessage());
- String elementNonValidato = null;
- try{
- elementNonValidato = this.xmlUtils.toString(node);
- }catch(Exception eString){
- this.log.error("Errore durante la conversione del Node in String: "+eString.getMessage(),eString);
- }
- this.log.error("Validazione fallita (elemento "+nomeElemento+") ["+elementNonValidato+"]: "+e.getMessage(),e);
- throw new WADLValidatorException(errorMsgValidazioneXSD.toString(),e);
- }
-
- }
- }catch(WADLException e){
- throw e;
- }catch(WADLValidatorException e){
- throw e;
- }catch(Exception e){
- throw new WADLException(e.getMessage(),e);
- }
- }
-
- }
-
- private AbstractNode getNode(HttpBaseEntity<?> httpEntity, MethodNode methodNode)throws WADLException,WADLValidatorException{
- // Navigare il methodNode secondo la seguente specifica:
- // Se siamo nella richiesta (httpEntity instanceof HttpRequestEntity)
- // verificare se esiste un input con mediaType 'application/xml (o text/xml)'
- // se esiste recuperare l'elementNameAtteso
- // else se siamo nella risposta (httpEntity instanceof HttpResponseEntity)
- // verificare se esiste un output o un fault con mediaType 'application/xml (o text/xml)' e status uguale a quello presente nella risposta http
- // se esiste recuperare l'elementNameAtteso
- if(httpEntity instanceof HttpBaseRequestEntity<?>) {
- if(methodNode.getSupportedInputs() != null) {
- for(RepresentationNode input: methodNode.getSupportedInputs()) {
- if(input.getMediaType().equals("application/xml") || input.getMediaType().equals("text/xml")) {
- return input;
- }
- }
- }
- } else if(httpEntity instanceof HttpBaseResponseEntity<?>) {
- int status = ((HttpBaseResponseEntity<?>)httpEntity).getStatus();
-
- List<RepresentationNode> lstOutputs = getSupportedOutputs(methodNode.getSupportedOutputs(), status);
- if(lstOutputs != null) {
- for(RepresentationNode output: lstOutputs) {
- if(output.getMediaType().equals("application/xml") || output.getMediaType().equals("text/xml")) {
- return output;
- }
- }
- }
- List<FaultNode> lstFaults = getSupportedFaults(methodNode.getFaults(), status);
- if(lstFaults != null) {
- for(FaultNode fault: lstFaults) {
- if(fault.getMediaType().equals("application/xml") || fault.getMediaType().equals("text/xml")) {
- return fault;
- }
- }
- }
-
- lstOutputs = methodNode.getSupportedOutputs().get(new ArrayList<Long>());
- if(lstOutputs != null) {
- for(RepresentationNode output: lstOutputs) {
- if(output.getMediaType().equals("application/xml") || output.getMediaType().equals("text/xml")) {
- return output;
- }
- }
- }
-
- }
-
- return null;
- }
-
- private List<RepresentationNode> getSupportedOutputs(MultivaluedMap<List<Long>, RepresentationNode> outputs,
- int status) {
- for(List<Long> lst: outputs.keySet()) {
- for(Long longValue: lst) {
- if(longValue.intValue() == status)
- return outputs.get(lst);
- }
- }
- return null;
- }
-
- private List<FaultNode> getSupportedFaults(MultivaluedMap<List<Long>, FaultNode> faults,
- int status) {
- for(List<Long> lst: faults.keySet()) {
- for(Long longValue: lst) {
- if(longValue.intValue() == status)
- return faults.get(lst);
- }
- }
- return null;
- }
-
- private void wadlConformanceCheck(HttpBaseEntity<?> httpEntity,ResourceNode resourceNode,MethodNode methodNode) throws WADLException,WADLValidatorException{
- try{
-
- javax.xml.namespace.QName elementAtteso = null;
- // ... altri vedere un po ....
- AbstractNode nodeXML = getNode(httpEntity, methodNode);
- if(nodeXML != null) {
- if(nodeXML instanceof RepresentationNode) {
- RepresentationNode representationNode = (RepresentationNode)nodeXML;
- elementAtteso = representationNode.getElement();
- } else if(nodeXML instanceof FaultNode) {
- FaultNode faultNode = (FaultNode)nodeXML;
- elementAtteso = faultNode.getElement();
- }
- }
-
-
- if(elementAtteso!=null){
-
- // Verifica rootNode
- Node node = this.readNode(elementAtteso, httpEntity);
- if(node.getLocalName()==null){
- throw new WADLValidatorException("Verifica presenza element ["+elementAtteso+"] fallita. Element presente nel payload http non contiene un local-name?");
- }
- if(node.getNamespaceURI()==null){
- throw new WADLValidatorException("Verifica presenza element ["+elementAtteso+"] fallita. Element presente nel payload http non contiene un namespace?");
- }
- if(node.getLocalName().equals(elementAtteso.getLocalPart())==false){
- throw new WADLValidatorException("Verifica presenza element ["+elementAtteso+"] fallita. Element presente nel payload http contiene un local-name ["+node.getLocalName()+"] differente da quello atteso ["+elementAtteso.getLocalPart()+"]");
- }
- if(node.getNamespaceURI().equals(elementAtteso.getNamespaceURI())==false){
- throw new WADLValidatorException("Verifica presenza element ["+elementAtteso+"] fallita. Element presente nel payload http contiene un namespace ["+node.getNamespaceURI()+"] differente da quello atteso ["+elementAtteso.getNamespaceURI()+"]");
- }
- }
- }catch(WADLException e){
- throw e;
- }catch(WADLValidatorException e){
- throw e;
- }catch(Exception e){
- throw new WADLException(e.getMessage(),e);
- }
-
- }
- private Node readNode(javax.xml.namespace.QName elementAtteso, HttpBaseEntity<?> httpEntity) throws WADLValidatorException, WADLException{
- Node node = null;
- try{
- if(httpEntity.getContent()==null){
- throw new WADLValidatorException("Verifica presenza element ["+elementAtteso+"] fallita. Non è stato riscontrato alcun dato nel payload http");
- }
- Object content = httpEntity.getContent();
-
- if(content instanceof Element){
- node = ((Element) content);
- }
- else if(content instanceof Document){
- node = ((Document) content).getDocumentElement();
- }
- else if(content instanceof byte[]){
- byte [] bytes = (byte[]) content;
- node = this.xmlUtils.newDocument(bytes);
- }
- else if(content instanceof String){
- byte [] bytes = ((String)content).getBytes();
- node = this.xmlUtils.newDocument(bytes);
- }
- else if(content instanceof InputStream){
- InputStream is = (InputStream) content;
- node = this.xmlUtils.newDocument(is);
- }
- else{
- throw new WADLException("HttpBaseEntity ["+httpEntity.getClass().getName()+"] non gestita");
- }
-
- return node;
-
-
- }catch(WADLException e){
- throw e;
- }catch(WADLValidatorException e){
- throw e;
- }catch(Exception e){
- throw new WADLValidatorException("Verifica presenza element ["+elementAtteso+"] fallita. Non è stato riscontrato nel payload http dei dati che contengano una struttura xml valida, "+e.getMessage(),e);
- }
- }
- }