IntegrationErrorConfiguration.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.message.config;

import java.util.List;

import org.openspcoop2.message.constants.IntegrationErrorMessageType;
import org.openspcoop2.message.constants.MessageType;
import org.openspcoop2.message.constants.ServiceBinding;
import org.openspcoop2.utils.transport.http.HttpConstants;
import org.openspcoop2.utils.transport.http.HttpServletTransportRequestContext;

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

public class IntegrationErrorConfiguration implements java.io.Serializable {

	/**
	 * serialVersionUID
	 */
	private static final long serialVersionUID = 1L;

	private IntegrationErrorMessageType errorType;
	private IntegrationErrorMessageType defaultErrorType;
	private ConfigurationRFC7807 rfc7807;
	private IntegrationErrorReturnConfiguration errorReturnConfig;
	private boolean useInternalFault; // in cooperazione
		
	public IntegrationErrorConfiguration(ConfigurationRFC7807 rfc7807, IntegrationErrorMessageType errorType, 
			IntegrationErrorReturnConfiguration errorReturnConfig,  
			boolean useInternalFault){
		this.rfc7807 = rfc7807;
		this.errorType = errorType;
		this.errorReturnConfig = errorReturnConfig;
		this.useInternalFault = useInternalFault;
	}
	
	void setDefaultErrorType(IntegrationErrorMessageType defaultErrorType) {
		this.defaultErrorType = defaultErrorType;
	}

	public ConfigurationRFC7807 getRfc7807() {
		return this.rfc7807;
	}
	public IntegrationErrorReturnConfiguration getErrorReturnConfig() {
		return this.errorReturnConfig;
	}
	public boolean isUseInternalFault() {
		return this.useInternalFault;
	}
	
	public MessageType getMessageType(HttpServletTransportRequestContext request, ServiceBinding serviceBinding, MessageType requestMsgType){
		if(ServiceBinding.REST.equals(serviceBinding) && this.rfc7807!=null) {
			if(this.rfc7807.isUseAcceptHeader() && request!=null && request.getHeaderValues(HttpConstants.ACCEPT)!=null && !request.getHeaderValues(HttpConstants.ACCEPT).isEmpty()) {
				List<String> values = request.getHeaderValues(HttpConstants.ACCEPT);
				// https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
				/*
				 * Example from rfc:
       				Accept: text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c
				    Verbally, this would be interpreted as "text/html and text/x-c are the preferred media types, but if they do not exist, then send the text/x-dvi entity, and if that does not exist, send the text/plain entity."
				 **/
				boolean readQparameter = true;
				MessageType mt = readMessageTypeFromAccept(values, !readQparameter); // prima priorità a quelli senza q parameter
				if(mt!=null) {
					return mt;
				}
				
				// altrimenti esamino quelli con q parameter
				mt = readMessageTypeFromAccept(values, readQparameter); // prima priorità a quelli senza q parameter
				if(mt!=null) {
					return mt;
				}
			}
		}
		
		switch (this.errorType) {
		case SOAP_AS_REQUEST:
			if(MessageType.SOAP_11.equals(requestMsgType) || MessageType.SOAP_12.equals(requestMsgType) )
				return requestMsgType;			
			return getDefaultMessageType(requestMsgType);
		case SOAP_11:
			return MessageType.SOAP_11;
		case SOAP_12:
			return MessageType.SOAP_12;
		case XML:
			return MessageType.XML;
		case JSON:
			return MessageType.JSON;
		case SAME_AS_REQUEST:
			if(MessageType.SOAP_11.equals(requestMsgType) || MessageType.SOAP_12.equals(requestMsgType) )
				return requestMsgType;
			if(MessageType.XML.equals(requestMsgType) || MessageType.JSON.equals(requestMsgType) )
				return requestMsgType;
			return getDefaultMessageType(requestMsgType);
		default:
			return MessageType.BINARY; // content is null
		}
	}
	public MessageType getDefaultMessageType(MessageType requestMsgType){
		switch (this.defaultErrorType) {
		case SOAP_11:
			return MessageType.SOAP_11;
		case SOAP_12:
			return MessageType.SOAP_12;
		case XML:
			return MessageType.XML;
		case JSON:
			return MessageType.JSON;
		default:
			return MessageType.BINARY; // content is null
		}
	}
	
	private MessageType readMessageTypeFromAccept(List<String> values, boolean readQparameter) {
		boolean asJson = false;
		boolean asXml = false;
		// https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
		for (String value : values) {
			String [] acceptHeaders = null;
			if(value.contains(",")) {
				acceptHeaders = value.split(",");
				for (int i = 0; i < acceptHeaders.length; i++) {
					acceptHeaders[i] = acceptHeaders[i].trim();
				}
			}
			else {
				acceptHeaders = new String [] {value.trim()};
			}
			double asJsonParamterQ = 0;
			double asXmlParamterQ = 0;
			for (String hdr : acceptHeaders) {
				if(readQparameter) {
					if(hdr.contains(";")) {
						String [] tmp = hdr.split(";");
						if(tmp!=null && tmp.length==2) {
							String mediaType = tmp[0];
							String q = tmp[1];
							if(mediaType!=null && q!=null) {
								q = q.trim();
								mediaType = mediaType.trim();
								if(q.contains("=")) {
									String [] tmpQ = q.split("=");
									if(tmpQ!=null && tmpQ.length==2) {
										String qParam = tmpQ[0];
										String qParamValue = tmpQ[1];
										if(qParam!=null && "q".equalsIgnoreCase(qParam.trim()) && qParamValue!=null) {
											double d = 0;
											try {
												d = Double.valueOf(qParamValue.trim());
												if(d>0) {
													if(isJsonMediaType(mediaType)){
														if(d>asJsonParamterQ) {
															asJsonParamterQ = d;
															asJson = true;
														}
													}
													else if(isXmlMediaType(mediaType)){
														if(d>asXmlParamterQ) {
															asXmlParamterQ = d;
															asXml = true;
														}
													}					
												}
											}catch(Throwable t) {}
										}
									}
								}
							}
						}
					}
				}
				else {
					if(isJsonMediaType(hdr)){
						asJson = true;
						break;
					}
					else if(isXmlMediaType(hdr)){
						asXml = true;
						break;
					}
				}
			}
			
			if(asJson && asXml && readQparameter) {
				if(asJsonParamterQ>asXmlParamterQ) {
					return MessageType.JSON;
				}
				else {
					return MessageType.XML;
				}
			}
			
			if(asJson) {
				return MessageType.JSON;
			}
			else if(asXml) {
				return MessageType.XML;
			}
		}
		return null;
	}
	private boolean isJsonMediaType(String hdrValue) {
		if(hdrValue.toLowerCase().endsWith("/x-json") || hdrValue.toLowerCase().endsWith("/json") || hdrValue.toLowerCase().endsWith("+json")){
			return true;
		}
		return false;
	}
	private boolean isXmlMediaType(String hdrValue) {
		if(hdrValue.toLowerCase().endsWith("/x-xml") || hdrValue.toLowerCase().endsWith("/xml") || hdrValue.toLowerCase().endsWith("+xml")){
			return true;
		}
		return false;
	}
}