AccordoServizioUtils.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.driver;

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 javax.xml.validation.Schema;

import org.slf4j.Logger;
import org.openspcoop2.core.registry.AccordoServizioParteComune;
import org.openspcoop2.core.registry.Documento;
import org.openspcoop2.core.registry.constants.CostantiRegistroServizi;
import org.openspcoop2.message.OpenSPCoop2MessageFactory;
import org.openspcoop2.message.xml.MessageXMLUtils;
import org.openspcoop2.utils.LoggerWrapperFactory;
import org.openspcoop2.utils.resources.FileSystemUtilities;
import org.openspcoop2.utils.transport.http.HttpUtilities;
import org.openspcoop2.utils.wsdl.WSDLUtilities;
import org.openspcoop2.utils.xml.AbstractXMLUtils;
import org.openspcoop2.utils.xml.XSDSchemaCollection;
import org.openspcoop2.utils.xml.XSDUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

/**
 * AccordoServizioUtils
 * 
 * @author Andrea Poli (apoli@link.it)
 * @author $Author$
 * @version $Rev$, $Date$
 *
 */
public class AccordoServizioUtils {

	private Logger logger = null;
	private AbstractXMLUtils xmlUtils = null;
	private XSDUtils xsdUtils = null;
	private OpenSPCoop2MessageFactory messageFactory;
	public AccordoServizioUtils(OpenSPCoop2MessageFactory messageFactory, Logger log){
		if(log!=null)
			this.logger = log;
		else
			this.logger = LoggerWrapperFactory.getLogger(AccordoServizioUtils.class);
		this.messageFactory = messageFactory;
		this.xmlUtils = MessageXMLUtils.getInstance(this.messageFactory);
		this.xsdUtils = new XSDUtils(this.xmlUtils);
	}
	
	


	
	public Schema buildSchema(AccordoServizioParteComune as,boolean fromBytes) throws DriverRegistroServiziException {
		XSDSchemaCollection schemaCollections = this.buildSchemaCollection(as, fromBytes);
		try{
			return schemaCollections.buildSchema(this.logger);
		}catch(Exception e){
			throw new DriverRegistroServiziException(e.getMessage(),e);
		}
	}
	public XSDSchemaCollection buildSchemaCollection(AccordoServizioParteComune as,boolean fromBytes) throws DriverRegistroServiziException {

		boolean definitorioPresente = false;
		if(fromBytes){
			definitorioPresente = as.getByteWsdlDefinitorio()!=null;
		}else{
			definitorioPresente = as.getWsdlDefinitorio()!=null;
		}
		
		List<Node> schemiInWsdl = new ArrayList<Node>();
		List<Node> schemiInWsdlFruitore = new ArrayList<Node>();
		WSDLUtilities wsdlUtilities = null;
		Document dWsdl = null;
		Document dWsdlFruitore = null;
		byte [] wsdl = null;
		byte [] wsdlFruitore = null;
		if(fromBytes){
			if(as.getByteWsdlConcettuale()!=null){
				wsdl = as.getByteWsdlConcettuale();
			}
			else{
				if(as.getByteWsdlLogicoErogatore()!=null){
					wsdl = as.getByteWsdlLogicoErogatore();
				}
				if(as.getByteWsdlLogicoFruitore()!=null){
					wsdlFruitore = as.getByteWsdlLogicoFruitore();
				}
			}
		}
		else{
			if(as.getWsdlConcettuale()!=null){
				try{
					String location = as.getWsdlConcettuale();
					if(location.startsWith("http://") || location.startsWith("file://")){
						URL url = new URL(location);
						wsdl = HttpUtilities.requestHTTPFile(url.toString());
					}
					else{
						File f = new File(location);
						wsdl = FileSystemUtilities.readBytesFromFile(f);
					}
				}catch(Exception e){
					throw new DriverRegistroServiziException("L'accordo di servizio parte comune contiene un wsdl concettuale corrotto: "+e.getMessage(),e);
				}
			}
			else{
				if(as.getWsdlLogicoErogatore()!=null){
					try{
						String location = as.getWsdlLogicoErogatore();
						if(location.startsWith("http://") || location.startsWith("file://")){
							URL url = new URL(location);
							wsdl = HttpUtilities.requestHTTPFile(url.toString());
						}
						else{
							File f = new File(location);
							wsdl = FileSystemUtilities.readBytesFromFile(f);
						}
					}catch(Exception e){
						throw new DriverRegistroServiziException("L'accordo di servizio parte comune contiene un wsdl logico erogatore corrotto: "+e.getMessage(),e);
					}
				}
				if(as.getWsdlLogicoFruitore()!=null){
					try{
						String location = as.getWsdlLogicoFruitore();
						if(location.startsWith("http://") || location.startsWith("file://")){
							URL url = new URL(location);
							wsdlFruitore = HttpUtilities.requestHTTPFile(url.toString());
						}
						else{
							File f = new File(location);
							wsdlFruitore = FileSystemUtilities.readBytesFromFile(f);
						}
					}catch(Exception e){
						throw new DriverRegistroServiziException("L'accordo di servizio parte comune contiene un wsdl logico fruitore corrotto: "+e.getMessage(),e);
					}
				}
			}
		}
		if(wsdl!=null){
			try{
				wsdlUtilities = new WSDLUtilities(this.xmlUtils);
				dWsdl = this.xmlUtils.newDocument(wsdl);
				List<Node> schemi = wsdlUtilities.getSchemiXSD(dWsdl);
				if(schemi!=null && schemi.size()>0){
					for (Node schema : schemi) {
						boolean schemaWithOnlyImport = this.xsdUtils.isSchemaWithOnlyImports(schema);
						if(schemaWithOnlyImport==false){
							schemiInWsdl.add(schema);		
						}
					}
				}
			}catch(Exception e){
				throw new DriverRegistroServiziException("L'accordo di servizio parte comune contiene un wsdl corrotto: "+e.getMessage(),e);
			}
		}
		if(wsdlFruitore!=null){
			try{
				wsdlUtilities = new WSDLUtilities(this.xmlUtils);
				dWsdlFruitore = this.xmlUtils.newDocument(wsdlFruitore);
				List<Node> schemi = wsdlUtilities.getSchemiXSD(dWsdlFruitore);
				if(schemi!=null && schemi.size()>0){
					for (Node schema : schemi) {
						boolean schemaWithOnlyImport = this.xsdUtils.isSchemaWithOnlyImports(schema);
						if(schemaWithOnlyImport==false){
							schemiInWsdlFruitore.add(schema);		
						}
					}
				}
			}catch(Exception e){
				throw new DriverRegistroServiziException("L'accordo di servizio parte comune contiene un wsdl fruitore corrotto: "+e.getMessage(),e);
			}
		}
		
		
		if( (schemiInWsdl.size()<=0) && (schemiInWsdlFruitore.size()<=0) && (!definitorioPresente) && as.sizeAllegatoList()==0 && as.sizeSpecificaSemiformaleList()==0){
			throw new DriverRegistroServiziException("L'accordo di servizio parte comune non contiene schemi XSD");
		}

		Map<String, byte[]> resources = new HashMap<String, byte[]>();
		Map<String, String> mappingNamespaceLocations = new HashMap<>();

		
		
		// --------- WSDL CONCETTUALE/LOGICO EROGATORE ---------------------
		if(schemiInWsdl.size()>0){

			Map<String, String> declarationNamespacesWSDL = null;
			try{
				declarationNamespacesWSDL = this.xmlUtils.getNamespaceDeclaration(dWsdl.getDocumentElement());
			}catch(Exception e){
				throw new DriverRegistroServiziException("L'accordo di servizio parte comune contiene un wsdl corrotto (Analisi namespace declarations): "+e.getMessage(),e);
			}
			for (int i = 0; i < schemiInWsdl.size(); i++) {
				Node schema = schemiInWsdl.get(i);
				try{
					if(declarationNamespacesWSDL!=null && declarationNamespacesWSDL.size()>0){
						this.xmlUtils.addNamespaceDeclaration(declarationNamespacesWSDL, (Element) schema);
					}
					byte[] resource = this.xmlUtils.toByteArray(schema); 
					String systemId = "internalWsdlTypes_"+(i+1)+".xsd";
					
					// registro risorsa con systemid
					//System.out.println("ADD CONCETTUALE ["+systemId+"] ");
					resources.put(systemId, resource);

					// registro namespace
					this.xsdUtils.registraMappingNamespaceLocations(resource, systemId, mappingNamespaceLocations);
					
				}catch(Exception e){
					throw new DriverRegistroServiziException("L'accordo di servizio parte comune contiene un wsdl corrotto (Estrazione schema): "+e.getMessage(),e);
				}
			}
		}
		
		// --------- WSDL CONCETTUALE/LOGICO EROGATORE ---------------------
		if(schemiInWsdlFruitore.size()>0){

			Map<String, String> declarationNamespacesWSDL = null;
			try{
				if(dWsdlFruitore!=null) {
					declarationNamespacesWSDL = this.xmlUtils.getNamespaceDeclaration(dWsdlFruitore.getDocumentElement());
				}
			}catch(Exception e){
				throw new DriverRegistroServiziException("L'accordo di servizio parte comune contiene un wsdl corrotto (Analisi namespace declarations): "+e.getMessage(),e);
			}
			for (int i = 0; i < schemiInWsdlFruitore.size(); i++) {
				Node schema = schemiInWsdlFruitore.get(i);
				try{
					if(declarationNamespacesWSDL!=null && declarationNamespacesWSDL.size()>0){
						this.xmlUtils.addNamespaceDeclaration(declarationNamespacesWSDL, (Element) schema);
					}
					byte[] resource = this.xmlUtils.toByteArray(schema); 
					String systemId = "internalWsdlFruitoreTypes_"+(i+1)+".xsd";
					
					// registro risorsa con systemid
					//System.out.println("ADD CONCETTUALE ["+systemId+"] ");
					resources.put(systemId, resource);

					// registro namespace
					this.xsdUtils.registraMappingNamespaceLocations(resource, systemId, mappingNamespaceLocations);
					
				}catch(Exception e){
					throw new DriverRegistroServiziException("L'accordo di servizio parte comune contiene un wsdl corrotto (Estrazione schema): "+e.getMessage(),e);
				}
			}
		}

		// --------- WSDL DEFINITORIO ---------------------
		if( (fromBytes && as.getByteWsdlDefinitorio()!=null) ||
				(!fromBytes && as.getWsdlDefinitorio()!=null)
				){

			byte[] resource = null;
			String systemId = null;
			if(fromBytes){
				systemId = CostantiRegistroServizi.ALLEGATO_DEFINITORIO_XSD;
				resource = as.getByteWsdlDefinitorio();
			}else{
				String location = as.getWsdlDefinitorio();
				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("L'accordo di servizio parte comune indirizza un wsdl definitorio ["+location+"] non esistente");
				}
			}

			try{
				if(this.xsdUtils.isXSDSchema(resource)){

					// registro risorsa con systemid
					//System.out.println("ADD DEFINITIORIO ["+systemId+"] ");
					resources.put(systemId, resource);

					// registro namespace
					this.xsdUtils.registraMappingNamespaceLocations(resource, systemId, mappingNamespaceLocations);
				}
			}catch(Exception e){
				throw new DriverRegistroServiziException("La lettura del wsdl definitorio ha causato un errore: "+e.getMessage(),e);
			}
		}

		// --------- 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(resources.containsKey(systemId)){
							throw new Exception("Esiste più di un documento xsd, registrato tra allegati e specifiche semiformali, con nome ["+systemId+"] (La validazione xsd di OpenSPCoop richiede l'utilizzo di nomi diversi)");
						}
						resources.put(systemId,resource); 

						// registro namespace
						this.xsdUtils.registraMappingNamespaceLocations(resource, systemId, mappingNamespaceLocations);
					}
				}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(resources.containsKey(systemId)){
							throw new Exception("Esiste più di un documento xsd, registrato tra allegati e specifiche semiformali, con nome ["+systemId+"] (La validazione xsd di OpenSPCoop richiede l'utilizzo di nomi diversi)");
						}
						resources.put(systemId,resource); 

						// registro namespace
						this.xsdUtils.registraMappingNamespaceLocations(resource, systemId, mappingNamespaceLocations);
					}
				}catch(Exception e){
					throw new DriverRegistroServiziException("La lettura della specifica semiformale ["+systemId+"] ha causato un errore: "+e.getMessage(),e);
				}

			}
		}

		try{
			return this.xsdUtils.buildSchemaCollection(resources, mappingNamespaceLocations, this.logger);
		}catch(Exception e){
			throw new DriverRegistroServiziException(e.getMessage(),e);
		}
			
	}

	
}