URLProtocolContextImpl.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.protocol.engine;

import javax.servlet.http.HttpServletRequest;

import org.openspcoop2.protocol.manifest.constants.Costanti;
import org.openspcoop2.protocol.sdk.IProtocolFactory;
import org.openspcoop2.protocol.sdk.ProtocolException;
import org.openspcoop2.protocol.sdk.constants.IDService;
import org.openspcoop2.protocol.sdk.state.FunctionContextsCustom;
import org.openspcoop2.utils.UtilsException;
import org.slf4j.Logger;

/**
 * URL Protocol Context
 *
 * @author Poli Andrea (apoli@link.it)
 * @author $Author$
 * @version $Rev$, $Date$
 */


public class URLProtocolContextImpl extends org.openspcoop2.protocol.sdk.state.URLProtocolContext implements java.io.Serializable {


	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	public URLProtocolContextImpl(Logger logCore) throws UtilsException{
		super(logCore);
	}
	public URLProtocolContextImpl(HttpServletRequest req,Logger logCore, boolean debug, FunctionContextsCustom customContexts) throws ProtocolException, UtilsException{
		super(req, logCore, debug, customContexts);
	}
	public URLProtocolContextImpl(HttpServletRequest req,Logger logCore, boolean debug, boolean integrationManagerEngine, FunctionContextsCustom customContexts) throws ProtocolException, UtilsException{
		super(req, logCore, debug, integrationManagerEngine, customContexts);
	}
	
	@Override
	protected void init(HttpServletRequest req,Logger logCore, boolean debug, boolean integrationManagerEngine, FunctionContextsCustom customContexts) throws ProtocolException, UtilsException{
				
		String servletContext = req.getContextPath();
		String urlInvocazione = req.getRequestURI();
		String servizioInvocato = null;
		if(logCore!=null)
			logCore.debug("SERVLET CONTEXT ["+servletContext+"] URL["+urlInvocazione+"]");
			// es SERVLET CONTEXT [/govway] URL[/govway/altriParametri]
		try {
			
			ProtocolFactoryManager protocolFactoryManager = ProtocolFactoryManager.getInstance();
			IProtocolFactory<?> pfEmptyContext = null;
			IDService idServiceDefaultEmptyContext = null;
			try {
				pfEmptyContext = protocolFactoryManager.getProtocolFactoryWithEmptyContext();
				idServiceDefaultEmptyContext = protocolFactoryManager.getDefaultServiceForEmptyContext();
			}catch(Throwable e) {
				// ignore
			}
			
			// Altro...
			if(urlInvocazione.startsWith(servletContext+"/")){
				servizioInvocato = urlInvocazione.substring((servletContext+"/").length());
			}
			else if(urlInvocazione.equals(servletContext)){
				servizioInvocato = null;
			}
			else {
				throw new Exception("GovWay [protocol/]service to be used not supplied (context error)");
			}
			
			
			if(logCore!=null)
				logCore.debug("SERVIZIO RICHIESTO: ["+servizioInvocato+"]");
			
			// verifico che dopo "openspcoop2" sia stato fornito qualcosa
			if(servizioInvocato==null || "".equals(servizioInvocato.trim())){
				if(pfEmptyContext!=null && idServiceDefaultEmptyContext!=null) {
					this.protocolName = pfEmptyContext.getProtocol();
					this.idServiceCustom = idServiceDefaultEmptyContext;
					switch (idServiceDefaultEmptyContext) {
					case PORTA_DELEGATA:
						this.function = org.openspcoop2.protocol.sdk.state.URLProtocolContext.PD_FUNCTION_GOVWAY;
						break;
					case PORTA_APPLICATIVA:
						this.function = org.openspcoop2.protocol.sdk.state.URLProtocolContext.PA_FUNCTION_GOVWAY;
						break;
					case PORTA_DELEGATA_XML_TO_SOAP:
						this.function = org.openspcoop2.protocol.sdk.state.URLProtocolContext.PDtoSOAP_FUNCTION_GOVWAY;
						break;
					default:
						throw new Exception("GovWay [protocol/]service to be used not supplied");
					}
					this.functionParameters = servizioInvocato;
					this.protocolWebContext = Costanti.CONTEXT_EMPTY;
				}
				else {
					throw new Exception("GovWay [protocol/]service to be used not supplied");
				}
			}
			else {
			
				// Esamino il servizio fornito. Puo' darsi che prima del servizio ci sia il protocollo.
				String protocollo = null;
				String function = null;
				String functionParameters = null;
				if(servizioInvocato.indexOf("/") >= 0){
					protocollo = servizioInvocato.substring(0,servizioInvocato.indexOf("/"));
					function = servizioInvocato.substring(servizioInvocato.indexOf("/")+1,servizioInvocato.length());
				}else{
					protocollo = servizioInvocato;
					function = servizioInvocato;
				}
				if(logCore!=null)
					logCore.debug("PROTOCOLLO["+protocollo+"] FUNCTION["+function+"]");
				
				// Vedo se ho un protocollo prima della funzione o direttamente il protocollo
				boolean IMengine = false;
				if(integrationManagerEngine && protocollo.equals(org.openspcoop2.protocol.sdk.state.URLProtocolContext.IntegrationManager_ENGINE)) {
					if(logCore!=null)
						logCore.debug("SERVLET INTEGRATION MANAGER SERVICE");
					function = protocollo;
					
					IMengine = true;
					
					Object o = getHttpServletRequest().getAttribute(org.openspcoop2.core.constants.Costanti.PROTOCOL_NAME.getValue());
					if(o == null || !(o instanceof String)){
						throw new Exception("Indicazione del protocollo non presente");
					}
					this.protocolName = (String) o;
					IProtocolFactory<?> pf = protocolFactoryManager.getProtocolFactoryByName(this.protocolName);
					if(pf==null){
						throw new Exception("Non risulta registrato un protocollo con nome ["+this.protocolName+"]");
					}
					
					o = getHttpServletRequest().getAttribute(org.openspcoop2.core.constants.Costanti.PROTOCOL_WEB_CONTEXT.getValue());
					if(o == null || !(o instanceof String)){
						throw new Exception("Indicazione del web context del protocollo non presente");
					}
					this.protocolWebContext = (String) o;
					pf = protocolFactoryManager.getProtocolFactoryByServletContext(this.protocolWebContext);
					if(pf==null){
						if(!Costanti.CONTEXT_EMPTY.equals(this.protocolWebContext))
							throw new Exception("Non risulta registrato un protocollo con contesto ["+this.protocolWebContext+"]");
						else
							throw new Exception("Non risulta registrato un protocollo con contesto speciale 'vuoto'");
					}
					
					int sizePrefix = (req.getContextPath() + "/" + function + "/").length();
					if(req.getRequestURI().length()>sizePrefix){
						functionParameters = req.getRequestURI().substring(sizePrefix);
					}
					
					if(functionParameters!=null && functionParameters.startsWith(IntegrationManager_SERVICE_PD)) {
						function+="_"+IntegrationManager_SERVICE_PD;
						
						Object oPD = getHttpServletRequest().getAttribute(org.openspcoop2.core.constants.Costanti.PORTA_DELEGATA.getValue());
						if(oPD == null || !(oPD instanceof String)){
							throw new Exception("Indicazione della porta delegata non presente");
						}
						
						functionParameters=(String)oPD;
						
					} 
					else if(functionParameters!=null && functionParameters.startsWith(IntegrationManager_SERVICE_MessageBox)) {
						function+="_"+IntegrationManager_SERVICE_MessageBox;
						
						if(functionParameters.length()>IntegrationManager_SERVICE_MessageBox.length()) {
							functionParameters = functionParameters.substring(IntegrationManager_SERVICE_MessageBox.length());
						}
	//					else {
	//						functionParameters = null;
	//					}
					}
				}
				else if(protocollo.equals(org.openspcoop2.protocol.sdk.state.URLProtocolContext.PA_FUNCTION) || 
						protocollo.equals(org.openspcoop2.protocol.sdk.state.URLProtocolContext.PD_FUNCTION) || 
						protocollo.equals(org.openspcoop2.protocol.sdk.state.URLProtocolContext.PDtoSOAP_FUNCTION) || 
						protocollo.equals(org.openspcoop2.protocol.sdk.state.URLProtocolContext.IntegrationManager_FUNCTION) ||
						protocollo.equals(org.openspcoop2.protocol.sdk.state.URLProtocolContext.Check_FUNCTION) ||
						protocollo.equals(org.openspcoop2.protocol.sdk.state.URLProtocolContext.Proxy_FUNCTION) ||
						(customContexts!=null && customContexts.isMatch(protocollo, function))) {
					// ContextProtocol Empty
					if(logCore!=null)
						logCore.debug("SERVLET PATH EMPTY");
					if((customContexts!=null && customContexts.isMatch(protocollo, function))) {
						this.idServiceCustom = customContexts.getServiceMatch(protocollo, function);
						function = customContexts.getFunctionMatch(protocollo, function);
						if(logCore!=null)
							logCore.debug("CUSTOM FUNCTION ["+function+"] ["+this.idServiceCustom+"]");
					}
					else {
						function = protocollo;
					}
					protocollo = Costanti.CONTEXT_EMPTY;
					
					int sizePrefix = (req.getContextPath() + "/" + function + "/").length();
					if(req.getRequestURI().length()>sizePrefix){
						functionParameters = req.getRequestURI().substring(sizePrefix);
					}
					else {
						// Serve nei casi custom
						functionParameters = null;
					}
				}
				else{
					// Verifico se esiste o meno il protocollo tra quelli registrati
					boolean casoSpeciale_noProtocollo_noFunction = false;
					try {
						IProtocolFactory<?> pfCheck = protocolFactoryManager.getProtocolFactoryByServletContext(protocollo);
						if(pfCheck==null) {
							throw new Exception("NotFound");
						}
					}catch(Exception e) {
						if(pfEmptyContext!=null) {
							if(function!=null && !"".equals(function)) {
								function = protocollo + "/" + function;
							}
							else {
								function = protocollo;
							}
							protocollo = Costanti.CONTEXT_EMPTY;
							casoSpeciale_noProtocollo_noFunction = true;
						}
					}
						
					
					// Calcolo function
					String functionParameterForCheckCustom = null;
					if(function.indexOf("/") > 0){
						functionParameterForCheckCustom = function.substring(function.indexOf("/"));
						if(functionParameterForCheckCustom.length()>1 && functionParameterForCheckCustom.startsWith("/")) {
							functionParameterForCheckCustom = functionParameterForCheckCustom.substring(1);
						}
					}
					if(function.indexOf("/") > 0){
						function = function.substring(0,function.indexOf("/"));
					}
					else if(function.indexOf("?") > 0){
						function = function.substring(0,function.indexOf("?"));
					}
					if(logCore!=null)
						logCore.debug("FUNCTION ["+function+"]");
					
					boolean emptyFunction = false;
					if(casoSpeciale_noProtocollo_noFunction ||
							(
									! (function.equals(org.openspcoop2.protocol.sdk.state.URLProtocolContext.PA_FUNCTION) || 
											function.equals(org.openspcoop2.protocol.sdk.state.URLProtocolContext.PD_FUNCTION) || 
											function.equals(org.openspcoop2.protocol.sdk.state.URLProtocolContext.PDtoSOAP_FUNCTION) || 
											function.equals(org.openspcoop2.protocol.sdk.state.URLProtocolContext.IntegrationManager_FUNCTION) ||
											function.equals(org.openspcoop2.protocol.sdk.state.URLProtocolContext.Check_FUNCTION) ||
											function.equals(org.openspcoop2.protocol.sdk.state.URLProtocolContext.Proxy_FUNCTION) ||
										(customContexts!=null && customContexts.isMatch(function, functionParameterForCheckCustom))) 
									)
							){
						IDService idS = null;
						if(casoSpeciale_noProtocollo_noFunction) {
							if(pfEmptyContext!=null && idServiceDefaultEmptyContext!=null) {
								idS = idServiceDefaultEmptyContext;							
							}
						}
						else {
							idS = protocolFactoryManager.getDefaultServiceForWebContext(protocollo);
						}
						if(idS!=null) {
							this.protocolName = pfEmptyContext.getProtocol();
							this.idServiceCustom = idS;
							switch (idS) {
							case PORTA_DELEGATA:
								function = org.openspcoop2.protocol.sdk.state.URLProtocolContext.PD_FUNCTION_GOVWAY;
								emptyFunction = true;
								break;
							case PORTA_APPLICATIVA:
								function = org.openspcoop2.protocol.sdk.state.URLProtocolContext.PA_FUNCTION_GOVWAY;
								emptyFunction = true;
								break;
							case PORTA_DELEGATA_XML_TO_SOAP:
								function = org.openspcoop2.protocol.sdk.state.URLProtocolContext.PDtoSOAP_FUNCTION_GOVWAY;
								emptyFunction = true;
								break;
							default:
							}
						}
					}
					
					StringBuilder bfSizePrefix = new StringBuilder(req.getContextPath());
					if(!Costanti.CONTEXT_EMPTY.equals(protocollo)) {
						bfSizePrefix.append("/").append(protocollo);
					}
					if(!emptyFunction) {
						bfSizePrefix.append("/").append(function);
					}
					bfSizePrefix.append("/");
					
					int sizePrefix = bfSizePrefix.length();
					if(req.getRequestURI().length()>sizePrefix){
						functionParameters = req.getRequestURI().substring(sizePrefix);
					}
					else {
						// Serve nei casi custom
						functionParameters = null;
					}
					
					if(!casoSpeciale_noProtocollo_noFunction && !emptyFunction) {
						if((customContexts!=null && customContexts.isMatch(function, functionParameters))) {
							this.idServiceCustom = customContexts.getServiceMatch(function, functionParameters);
							function = customContexts.getFunctionMatch(function, functionParameters);
							if(logCore!=null)
								logCore.debug("CUSTOM FUNCTION ["+function+"] ["+this.idServiceCustom+"]");
							// ricalcolo function parameters
							sizePrefix = (req.getContextPath() + "/"+ protocollo + "/" + function + "/").length();
							if(req.getRequestURI().length()>sizePrefix){
								functionParameters = req.getRequestURI().substring(sizePrefix);
							}
							else {
								// Serve nei casi custom
								functionParameters = null;
							}
						}
					}
					
					if(casoSpeciale_noProtocollo_noFunction && emptyFunction) {
						this.requestURI = this.requestURI.replace(servletContext+"/", servletContext+"/"+function+"/");
					}
					else if(emptyFunction) {
						this.requestURI = this.requestURI.replace(servletContext+"/"+protocollo+"/", servletContext+"/"+protocollo+"/"+function+"/");
					}
				}
										
				if(logCore!=null)
					logCore.debug("Elaborazione finale Protocollo["+protocollo+"] Function["+function+"] FunctionParameters ["+functionParameters+"]");
				
				if(!IMengine) {
					this.protocolWebContext = protocollo;
					IProtocolFactory<?> pf = protocolFactoryManager.getProtocolFactoryByServletContext(this.protocolWebContext);
					if(pf==null){
						if(!Costanti.CONTEXT_EMPTY.equals(this.protocolWebContext))
							throw new Exception("Non risulta registrato un protocollo con contesto ["+this.protocolWebContext+"]");
						else
							throw new Exception("Non risulta registrato un protocollo con contesto speciale 'vuoto'");
					}
					this.protocolName = pf.getProtocol();
				}
	
				this.function = function;
				this.functionParameters = functionParameters;
				
			}
			
		}catch(Exception e){
			throw new ProtocolException(e.getMessage(),e);
		}
	}
	
	@Override
	public String toString() {
		return this.toString("");
	}
	@Override
	public String toString(String prefix) {
		StringBuilder sb = new StringBuilder(super.toString(prefix));
		if(this.idServiceCustom!=null) {
			sb.append("\n").append(prefix).append("idServiceCustom: ").append(this.idServiceCustom);
		}
		return sb.toString();
	}
}