AccordoServizioWrapperUtilities.java

/*
 * GovWay - A customizable API Gateway 
 * https://govway.org
 * 
 * Copyright (c) 2005-2024 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.core.registry.rest;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.openspcoop2.core.registry.AccordoServizioParteComune;
import org.openspcoop2.core.registry.Documento;
import org.openspcoop2.core.registry.constants.FormatoSpecifica;
import org.openspcoop2.core.registry.driver.DriverRegistroServiziException;
import org.openspcoop2.message.OpenSPCoop2MessageFactory;
import org.openspcoop2.message.xml.MessageXMLUtils;
import org.openspcoop2.utils.LoggerWrapperFactory;
import org.openspcoop2.utils.json.JSONUtils;
import org.openspcoop2.utils.json.YAMLUtils;
import org.openspcoop2.utils.resources.FileSystemUtilities;
import org.openspcoop2.utils.rest.ApiFactory;
import org.openspcoop2.utils.rest.ApiFormats;
import org.openspcoop2.utils.rest.ApiReaderConfig;
import org.openspcoop2.utils.rest.IApiReader;
import org.openspcoop2.utils.rest.api.Api;
import org.openspcoop2.utils.rest.api.ApiSchema;
import org.openspcoop2.utils.rest.api.ApiSchemaType;
import org.openspcoop2.utils.transport.http.HttpUtilities;
import org.openspcoop2.utils.xml.AbstractXMLUtils;
import org.openspcoop2.utils.xml.XSDUtils;
import org.slf4j.Logger;


/**
 * Classe utilizzata per leggere/modificare i wsdl che formano un accordo di un servizio
 *
 *
 * @author Poli Andrea (apoli@link.it)
 * @author $Author$
 * @version $Rev$, $Date$
 */


public class AccordoServizioWrapperUtilities {

	private Logger logger = null;
	private AbstractXMLUtils xmlUtils = null;
	private XSDUtils xsdUtils = null;
	private JSONUtils jsonUtils = null;
	private YAMLUtils yamlUtils = null;
	private OpenSPCoop2MessageFactory messageFactory;
	
	/** Accordo Servizio */
	public AccordoServizioWrapperUtilities(OpenSPCoop2MessageFactory messageFactory, Logger log, AccordoServizioWrapper accordoServizio){
		if(log!=null)
			this.logger = log;
		else
			this.logger = LoggerWrapperFactory.getLogger(AccordoServizioWrapperUtilities.class);
		this.accordoServizioWrapper = accordoServizio;
		this.messageFactory = messageFactory;
		this.xmlUtils = MessageXMLUtils.getInstance(this.messageFactory);
		this.xsdUtils = new XSDUtils(this.xmlUtils);
		this.jsonUtils = JSONUtils.getInstance();
		this.yamlUtils = YAMLUtils.getInstance();
	}
	private AccordoServizioWrapper accordoServizioWrapper = null;
	public AccordoServizioWrapper getAccordoServizioWrapper() {
		return this.accordoServizioWrapper;
	}
	public void setAccordoServizio(AccordoServizioWrapper accordoServizio) {
		this.accordoServizioWrapper = accordoServizio;
	}
	
	
	
	
	
	public static final String API_SENZA_SPECIFICA = "L'API non contiene una specifica";
	
	public void buildApiFromSpecific(boolean fromBytes,boolean buildSchemi,boolean processInclude) throws DriverRegistroServiziException {
		
		if(this.accordoServizioWrapper==null) {
			throw new DriverRegistroServiziException("AccordoWrapper non fornito");
		}
		if(this.accordoServizioWrapper.getAccordoServizio()==null) {
			throw new DriverRegistroServiziException("API non fornita");
		}
		AccordoServizioParteComune as = this.accordoServizioWrapper.getAccordoServizio();
		
		IApiReader apiReader = null;
		FormatoSpecifica formato = as.getFormatoSpecifica();
		if(formato==null) {
			formato = FormatoSpecifica.OPEN_API_3;
		}
		switch (formato) {
		case WADL:
			try {
				apiReader = ApiFactory.newApiReader(ApiFormats.WADL);
			}catch(Exception e) {
				throw new DriverRegistroServiziException("Inizializzazione Reader Specifica ["+this.accordoServizioWrapper.getAccordoServizio().getFormatoSpecifica()+"] fallito: "+e.getMessage(),e);
			}
			break;
		case SWAGGER_2:
			try {
				apiReader = ApiFactory.newApiReader(ApiFormats.SWAGGER_2);
			}catch(Exception e) {
				throw new DriverRegistroServiziException("Inizializzazione Reader Specifica ["+this.accordoServizioWrapper.getAccordoServizio().getFormatoSpecifica()+"] fallito: "+e.getMessage(),e);
			}
			break;
		case OPEN_API_3:
			try {
				apiReader = ApiFactory.newApiReader(ApiFormats.OPEN_API_3);
			}catch(Exception e) {
				throw new DriverRegistroServiziException("Inizializzazione Reader Specifica ["+this.accordoServizioWrapper.getAccordoServizio().getFormatoSpecifica()+"] fallito: "+e.getMessage(),e);
			}
			break;
		case WSDL_11:
			throw new DriverRegistroServiziException("Tipo specifica ["+this.accordoServizioWrapper.getAccordoServizio().getFormatoSpecifica()+"] non supportata");
		}
		
		if(apiReader==null) {
			throw new DriverRegistroServiziException("Inizializzazione Reader Specifica ["+this.accordoServizioWrapper.getAccordoServizio().getFormatoSpecifica()+"] fallita");
		}
		
		
		byte [] specifica = null;
		if(fromBytes){
			if(as.getByteWsdlConcettuale()!=null){
				specifica = as.getByteWsdlConcettuale();
			}
		}
		else{
			if(as.getWsdlConcettuale()!=null){
				try{
					String location = as.getWsdlConcettuale();
					if(location.startsWith("http://") || location.startsWith("file://")){
						URL url = new URL(location);
						specifica = HttpUtilities.requestHTTPFile(url.toString());
					}
					else{
						File f = new File(location);
						specifica = FileSystemUtilities.readBytesFromFile(f);
					}
				}catch(Exception e){
					throw new DriverRegistroServiziException("L'API contiene una specifica corrotta: "+e.getMessage(),e);
				}
			}
		}
		if(specifica==null) {
			throw new DriverRegistroServiziException(API_SENZA_SPECIFICA);
		}
		
		
		
		ApiSchema [] s = null;
		ApiReaderConfig config = new ApiReaderConfig();
		if(buildSchemi) {
			config.setProcessInclude(processInclude);
			config.setProcessInlineSchema(true);
			s = this.buildSchemas(as, fromBytes);
		}
		else {
			config.setProcessInclude(false);
			config.setProcessInlineSchema(false);
		}
		try {
			if(s!=null) {
				apiReader.init(this.logger, specifica, config, s);
			}
			else {
				apiReader.init(this.logger, specifica, config);
			}
			Api api = apiReader.read();
			this.accordoServizioWrapper.setApi(api);
		}catch(Exception e) {
			throw new DriverRegistroServiziException("Inizializzazione Specifica ["+this.accordoServizioWrapper.getAccordoServizio().getFormatoSpecifica()+"] fallita: "+e.getMessage(),e);
		}
		
		
	}
	
	
	public void buildApiFromRegistry(boolean fromBytes,boolean buildSchemi) throws DriverRegistroServiziException {
			
		if(this.accordoServizioWrapper==null) {
			throw new DriverRegistroServiziException("AccordoWrapper non fornito");
		}
		if(this.accordoServizioWrapper.getAccordoServizio()==null) {
			throw new DriverRegistroServiziException("API non fornita");
		}
		AccordoServizioParteComune as = this.accordoServizioWrapper.getAccordoServizio();
		
		try {
			RegistryAPI api = new RegistryAPI(as, "http://TODO");
			
			ApiSchema [] s = null;
			if(buildSchemi) {
				s = this.buildSchemas(as, fromBytes);
				if(s!=null && s.length>0) {
					for (int i = 0; i < s.length; i++) {
						api.addSchema(s[i]);
					}
				}
			}
			
			this.accordoServizioWrapper.setApi(api);
		}catch(Exception e) {
			throw new DriverRegistroServiziException("Inizializzazione Specifica ["+this.accordoServizioWrapper.getAccordoServizio().getFormatoSpecifica()+"] fallita: "+e.getMessage(),e);
		}
	}
	
	
	private ApiSchema [] buildSchemas(AccordoServizioParteComune as, boolean fromBytes) throws DriverRegistroServiziException{
		Map<String, byte[]> resourcesXSD = new HashMap<String, byte[]>();
		Map<String, byte[]> resourcesJSON = new HashMap<String, byte[]>();
		Map<String, byte[]> resourcesYAML = new HashMap<String, byte[]>();
		
		// --------- ALLEGATI --------- 
		if(as.sizeAllegatoList()>0){
			for(int i=0; i<as.sizeAllegatoList();i++){

				Documento allegato = as.getAllegato(i);
				byte[] resource = null;
				String systemId = null;
				//String location = null;
				if(fromBytes){
					//location = allegato.getFile();
					systemId = allegato.getFile();
					resource = allegato.getByteContenuto();
					if(resource==null){
						throw new DriverRegistroServiziException("Allegato ["+systemId+"] non contiene i bytes che ne definiscono il contenuto");
					}
				}
				else{
					String location = allegato.getFile();
					try{
						if(location.startsWith("http://") || location.startsWith("file://")){
							URL url = new URL(location);
							resource = HttpUtilities.requestHTTPFile(url.toString());
							systemId = (new File(url.getFile())).getName();
						}
						else{
							File f = new File(location);
							resource = FileSystemUtilities.readBytesFromFile(f);
							systemId = f.getName();
						}	
					}catch(Exception e){
						throw new DriverRegistroServiziException("Allegato ["+location+"] indirizza un documento non esistente");
					}
				}

				try{
					if(this.xsdUtils.isXSDSchema(resource)){
						if(resourcesXSD.containsKey(systemId)){
							throw new Exception("Esiste più di un documento xsd, registrato tra allegati e specifiche semiformali, con nome ["+systemId+"] (La validazione di Govway richiede l'utilizzo di nomi diversi)");
						}
						resourcesXSD.put(systemId,resource); 
					}
					else if(this.yamlUtils.isYaml(resource)){
						if(resourcesYAML.containsKey(systemId)){
							throw new Exception("Esiste più di un documento yaml, registrato tra allegati e specifiche semiformali, con nome ["+systemId+"] (La validazione di Govway richiede l'utilizzo di nomi diversi)");
						}
						resourcesYAML.put(systemId,resource); 
					}
					else if(this.jsonUtils.isJson(resource)){
						if(resourcesJSON.containsKey(systemId)){
							throw new Exception("Esiste più di un documento json, registrato tra allegati e specifiche semiformali, con nome ["+systemId+"] (La validazione di Govway richiede l'utilizzo di nomi diversi)");
						}
						resourcesJSON.put(systemId,resource); 
					}
				}catch(Exception e){
					throw new DriverRegistroServiziException("La lettura dell'allegato ["+systemId+"] ha causato un errore: "+e.getMessage(),e);
				}

			}
		}


		// --------- SPECIFICHE SEMIFORMALI --------- 
		if(as.sizeSpecificaSemiformaleList()>0){
			for(int i=0; i<as.sizeSpecificaSemiformaleList();i++){

				Documento specificaSemiformale = as.getSpecificaSemiformale(i);
				byte[] resource = null;
				String systemId = null;
				//String location = null;
				if(fromBytes){
					//location = specificaSemiformale.getFile();
					systemId = specificaSemiformale.getFile();
					resource = specificaSemiformale.getByteContenuto();
					if(resource==null){
						throw new DriverRegistroServiziException("Specifica Semiformale ["+systemId+"] non contiene i bytes che ne definiscono il contenuto");
					}
				}
				else{
					String location = specificaSemiformale.getFile();
					try{
						if(location.startsWith("http://") || location.startsWith("file://")){
							URL url = new URL(location);
							resource = HttpUtilities.requestHTTPFile(url.toString());
							systemId = (new File(url.getFile())).getName();
						}
						else{
							File f = new File(location);
							resource = FileSystemUtilities.readBytesFromFile(f);
							systemId = f.getName();
						}	
					}catch(Exception e){
						throw new DriverRegistroServiziException("Specifica Semiformale ["+location+"] indirizza un documento non esistente");
					}
				}

				try{
					if(this.xsdUtils.isXSDSchema(resource)){
						if(resourcesXSD.containsKey(systemId)){
							throw new Exception("Esiste più di un documento xsd, registrato tra allegati e specifiche semiformali, con nome ["+systemId+"] (La validazione di Govway richiede l'utilizzo di nomi diversi)");
						}
						resourcesXSD.put(systemId,resource); 
					}
					else if(this.yamlUtils.isYaml(resource)){
						if(resourcesYAML.containsKey(systemId)){
							throw new Exception("Esiste più di un documento yaml, registrato tra allegati e specifiche semiformali, con nome ["+systemId+"] (La validazione di Govway richiede l'utilizzo di nomi diversi)");
						}
						resourcesYAML.put(systemId,resource); 
					}
					else if(this.jsonUtils.isJson(resource)){
						if(resourcesJSON.containsKey(systemId)){
							throw new Exception("Esiste più di un documento json, registrato tra allegati e specifiche semiformali, con nome ["+systemId+"] (La validazione di Govway richiede l'utilizzo di nomi diversi)");
						}
						resourcesJSON.put(systemId,resource); 
					}
				}catch(Exception e){
					throw new DriverRegistroServiziException("La lettura della specifica semiformale ["+systemId+"] ha causato un errore: "+e.getMessage(),e);
				}

			}
		}

		List<ApiSchema> schemas = new ArrayList<ApiSchema>();
		if(resourcesXSD!=null && resourcesXSD.size()>0) {
			for (String key : resourcesXSD.keySet()) {
				byte[] value = resourcesXSD.get(key);
				schemas.add(new ApiSchema(key, value, ApiSchemaType.XSD));
			}
		}
		if(resourcesYAML!=null && resourcesYAML.size()>0) {
			for (String key : resourcesYAML.keySet()) {
				byte[] value = resourcesYAML.get(key);
				schemas.add(new ApiSchema(key, value, ApiSchemaType.YAML));
			}
		}
		if(resourcesJSON!=null && resourcesJSON.size()>0) {
			for (String key : resourcesJSON.keySet()) {
				byte[] value = resourcesJSON.get(key);
				schemas.add(new ApiSchema(key, value, ApiSchemaType.JSON));
			}
		}
		ApiSchema [] s = null;
		if(schemas.size()>0) {
			s = schemas.toArray(new ApiSchema[1]);
		}
		
		return s;
	}
}