OperationFinder.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.mapping;
import org.openspcoop2.core.config.driver.DriverConfigurazioneException;
import org.openspcoop2.core.config.driver.DriverConfigurazioneNotFound;
import org.openspcoop2.core.id.IDServizio;
import org.openspcoop2.core.id.IDSoggetto;
import org.openspcoop2.core.registry.Operation;
import org.openspcoop2.core.registry.PortType;
import org.openspcoop2.core.registry.Resource;
import org.openspcoop2.core.registry.driver.DriverRegistroServiziException;
import org.openspcoop2.core.registry.driver.DriverRegistroServiziNotFound;
import org.openspcoop2.core.registry.wsdl.WSDLValidatorConfig;
import org.openspcoop2.message.MessageUtils;
import org.openspcoop2.message.OpenSPCoop2Message;
import org.openspcoop2.message.constants.MessageType;
import org.openspcoop2.message.constants.ServiceBinding;
import org.openspcoop2.message.rest.RestUtilities;
import org.openspcoop2.message.soap.SoapUtils;
import org.openspcoop2.message.soap.reader.OpenSPCoop2MessageSoapStreamReader;
import org.openspcoop2.protocol.engine.constants.ModalitaIdentificazioneAzione;
import org.openspcoop2.protocol.registry.RegistroServiziManager;
import org.openspcoop2.protocol.sdk.Busta;
import org.openspcoop2.protocol.sdk.IProtocolFactory;
import org.openspcoop2.protocol.sdk.constants.InformationApiSource;
import org.openspcoop2.protocol.sdk.state.RequestInfo;
import org.openspcoop2.protocol.utils.PorteNamingUtils;
import org.openspcoop2.utils.regexp.RegularExpressionEngine;
import org.openspcoop2.utils.rest.api.ApiOperation;
import org.openspcoop2.utils.transport.TransportRequestContext;
import org.openspcoop2.utils.transport.http.HttpRequestMethod;
import org.openspcoop2.utils.xml.AbstractXPathExpressionEngine;
import org.openspcoop2.utils.xml2json.JsonXmlPathExpressionEngine;
import org.slf4j.Logger;
import org.w3c.dom.Element;
/**
* OperationFinder
*
* @author Andrea Poli (apoli@link.it)
* @author $Author$
* @version $Rev$, $Date$
*/
public class OperationFinder {
private OperationFinder() {}
private static String getPrefixIdentificazione(ModalitaIdentificazioneAzione modalitaIdentificazione) {
return "Identificazione '"+modalitaIdentificazione.getValue()+"' ";
}
public static String getAzione(RegistroServiziManager registroServiziManager,TransportRequestContext transportContext, RequestInfo requestInfo,
OpenSPCoop2Message message, OpenSPCoop2MessageSoapStreamReader soapStreamReader,
IDSoggetto soggettoErogatore, IDServizio idServizio,
boolean readFirstHeaderIntegrazione, String azioneHeaderIntegrazione,
IProtocolFactory<?> protocolFactory,
ModalitaIdentificazioneAzione modalitaIdentificazione, String pattern,
boolean forceRegistryBased, boolean forcePluginBased,
Logger log, boolean portaApplicativa,
boolean bufferMessageReadOnly , String idTransazione,
WSDLValidatorConfig config) throws DriverConfigurazioneException, IdentificazioneDinamicaException {
try{
if(soggettoErogatore!=null) {
// nop
}
// Recupero Lista di Azioni
/**
List<String> listaAzioni = new ArrayList<>();
boolean rest = false;
try {
AccordoServizioParteSpecifica asps = registroServiziManager.getAccordoServizioParteSpecifica(idServizio, null, false);
AccordoServizioParteComune aspc = registroServiziManager.getAccordoServizioParteComune(IDAccordoFactory.getInstance().getIDAccordoFromUri(asps.getAccordoServizioParteComune()), null, false);
if(org.openspcoop2.core.registry.constants.ServiceBinding.REST.equals(aspc.getServiceBinding())) {
rest = true;
for (Resource r : aspc.getResourceList()) {
listaAzioni.add(r.getNome());
}
}
else {
if(asps.getPortType()==null) {
for (Azione a : aspc.getAzioneList()) {
listaAzioni.add(a.getNome());
}
}
else {
for (PortType pt: aspc.getPortTypeList()) {
if(pt.getNome().equals(asps.getPortType())) {
for (Operation a : pt.getAzioneList()) {
listaAzioni.add(a.getNome());
}
break;
}
}
}
}
}catch(Throwable t) {
// ignoro errori, li sollevo in altri posti
}*/
boolean registryBased = false;
boolean pluginBased = false;
String azione = null;
Exception eAzione = null;
try{
if(ModalitaIdentificazioneAzione.STATIC.equals(modalitaIdentificazione)){
// STATIC-BASED
azione = idServizio.getAzione();
}
else{
if(readFirstHeaderIntegrazione && azioneHeaderIntegrazione!=null){
// INTEGRATIONMANAGER INPUT
azione = azioneHeaderIntegrazione;
}
else{
if(ModalitaIdentificazioneAzione.URL_BASED.equals(modalitaIdentificazione)){
// URL-BASED
String urlInvocazionePD = transportContext.getUrlInvocazione_formBased();
azione = RegularExpressionEngine.getStringFindPattern(urlInvocazionePD, pattern); // Sostituito Match con Find per applicare l'espressione regolare che risolve il bug OP-1590
if(ServiceBinding.REST.equals(message.getServiceBinding())){
throw new DriverConfigurazioneNotFound(getPrefixIdentificazione(modalitaIdentificazione)+
"non supportata per il service binding '"+ServiceBinding.REST+"'");
}
}
else if(ModalitaIdentificazioneAzione.HEADER_BASED.equals(modalitaIdentificazione)){
// HEADER-BASED
azione = transportContext.getHeaderFirstValue(pattern);
}
else if(ModalitaIdentificazioneAzione.CONTENT_BASED.equals(modalitaIdentificazione)){
// CONTENT-BASED
if(message==null){
throw new DriverConfigurazioneNotFound("Messaggio non fornito");
}
AbstractXPathExpressionEngine xPathEngine = null;
Element element = null;
String elementJson = null;
boolean checkSoapBodyEmpty = false; // devo poter fare xpath anche su soapBody empty
if(message!=null) {
element = MessageUtils.getContentElement(message, checkSoapBodyEmpty, bufferMessageReadOnly, idTransazione);
elementJson = MessageUtils.getContentString(message, bufferMessageReadOnly, idTransazione);
}
if(element!=null) {
xPathEngine = new org.openspcoop2.message.xml.XPathExpressionEngine(message.getFactory());
azione = AbstractXPathExpressionEngine.extractAndConvertResultAsString(element, xPathEngine, pattern, log);
}
else if(elementJson!=null){
azione = JsonXmlPathExpressionEngine.extractAndConvertResultAsString(elementJson, pattern, log);
}
else{
throw new DriverConfigurazioneNotFound(getPrefixIdentificazione(modalitaIdentificazione)+"non supportata per il message-type '"+message.getMessageType()+"'");
}
}
else if(ModalitaIdentificazioneAzione.INPUT_BASED.equals(modalitaIdentificazione)){
// INPUT-BASED
if(azioneHeaderIntegrazione!=null){
azione = azioneHeaderIntegrazione;
}
else{
throw new DriverConfigurazioneNotFound("Azione non indicata negli header di integrazione");
}
}
else if(ModalitaIdentificazioneAzione.SOAP_ACTION_BASED.equals(modalitaIdentificazione)){
// SOAP-ACTION-BASED
if(message!=null && ServiceBinding.REST.equals(message.getServiceBinding())){
throw new DriverConfigurazioneNotFound(getPrefixIdentificazione(modalitaIdentificazione)+
"non supportata per il service binding '"+ServiceBinding.REST+"'");
}
if(message!=null){
azione = message.castAsSoap().getSoapAction();
}
else{
// provo una soluzione veloce di vedere se è presente nell'header di trasporto o nel content-type
// non so che tipo di message type possiedo
azione = getSoapAction(transportContext);
}
String azioneNonRipulita = azione;
if(azione!=null){
azione = azione.trim();
// Nota: la soap action potrebbe essere quotata con ""
if(azione.startsWith("\"")){
azione = azione.substring(1);
}
if(azione.endsWith("\"")){
azione = azione.substring(0,(azione.length()-1));
}
}
// Provo a fare la traduzione tramite soapAction registrata nell'accordo
if(azioneNonRipulita!=null || azione!=null) {
org.openspcoop2.core.registry.wsdl.AccordoServizioWrapper wrapper = registroServiziManager.getWsdlAccordoServizio(idServizio,InformationApiSource.SAFE_SPECIFIC_REGISTRY,false,false, requestInfo);
if(wrapper!=null){
for (int i = 0; i < wrapper.sizePortTypeList(); i++) {
PortType pt = wrapper.getPortType(i);
if(wrapper.getNomePortType()!=null &&
!pt.getNome().equals(wrapper.getNomePortType())){
continue;
}
for (int j = 0; j < pt.sizeAzioneList(); j++) {
Operation op = pt.getAzione(j);
if(
(azioneNonRipulita!=null && azioneNonRipulita.equals(op.getSoapAction()))
||
(azione!=null && azione.equals(op.getSoapAction()))
) {
/**System.out.println("RESOLVE 1 ["+azioneNonRipulita+"]");*/
/**System.out.println("RESOLVE 2 ["+azione+"]");*/
azione = op.getNome();
break;
}
}
}
}
}
if(azione!=null &&
"".equals(azione)){
azione = null;
throw new DriverConfigurazioneNotFound("SoapAction vuota ("+message.castAsSoap().getSoapAction()+") non è utilizzabile con una identificazione '"+
ModalitaIdentificazioneAzione.SOAP_ACTION_BASED.getValue()+"'");
}
}
else if(ModalitaIdentificazioneAzione.INTERFACE_BASED.equals(modalitaIdentificazione)){
// INTERFACE-BASED
registryBased = true;
OperationFinder.checkIDServizioPerRiconoscimentoAzione(idServizio, modalitaIdentificazione);
org.openspcoop2.core.registry.constants.ServiceBinding serviceBinding = registroServiziManager.getServiceBinding(idServizio, requestInfo);
if(org.openspcoop2.core.registry.constants.ServiceBinding.SOAP.equals(serviceBinding)){
azione = OperationFinder.searchOperationByWsdlInRequestMessage(message, soapStreamReader, requestInfo, registroServiziManager, idServizio, log,
config);
}
else {
azione = OperationFinder.searchOperationByRestInRequestMessage(transportContext, requestInfo, registroServiziManager, idServizio, log,
protocolFactory, portaApplicativa);
}
}
else if(ModalitaIdentificazioneAzione.PROTOCOL_BASED.equals(modalitaIdentificazione)){
// PROTOCOL-BASED
pluginBased = true;
if(idServizio.getAzione()!=null){
// gia localizzata in precedenza
azione = idServizio.getAzione();
}
else{
OpenSPCoop2Message msgAnalizyProtocol = message;
if(message==null && soapStreamReader!=null) {
msgAnalizyProtocol=soapStreamReader.getHeader_OpenSPCoop2Message();
}
if(msgAnalizyProtocol==null){
throw new DriverConfigurazioneNotFound("Messaggio non fornito");
}
Busta busta = protocolFactory.createValidazioneSintattica(null).getBusta_senzaControlli(msgAnalizyProtocol);
if(busta!=null){
azione = busta.getAzione();
}
}
}
}
}
}catch(Exception e){
eAzione = e;
}
// Se non ho riconosciuto una azione, provo con la modalita' wsdlBased se e' abilitata.
if(azione==null && forceRegistryBased && !registryBased ){
azione = getActionByInterface(log,
transportContext, idServizio, modalitaIdentificazione,
registroServiziManager, requestInfo,
message, soapStreamReader,
protocolFactory,
portaApplicativa,
config);
}
// Se non ho riconosciuto una azione, provo con la modalita' pluginBased se e' abilitata.
if(azione==null && forcePluginBased && !pluginBased ){
azione = getActionByPlugin(log,
idServizio,
message, soapStreamReader,
protocolFactory);
}
// Se non ho riconosciuto una azione a questo punto, e durante il processo standard di riconoscimento era stato sollevata una eccezione
// viene rilanciato
if(azione==null && eAzione!=null)
throw new IdentificazioneDinamicaException(eAzione.getMessage(),eAzione);
return azione;
}catch(IdentificazioneDinamicaException e){
throw e;
}
catch(Exception e){
throw new DriverConfigurazioneException(e.getMessage(),e);
}
}
private static String getSoapAction(TransportRequestContext transportContext) {
String azione = null;
try{
azione = SoapUtils.getSoapAction(transportContext, MessageType.SOAP_11, transportContext.getContentType());
}catch(Exception e){
// ignore
}
if(azione==null){
try{
azione = SoapUtils.getSoapAction(transportContext, MessageType.SOAP_12, transportContext.getContentType());
}catch(Exception e){
// ignore
}
}
return azione;
}
private static String getActionByInterface(Logger log,
TransportRequestContext transportContext, IDServizio idServizio, ModalitaIdentificazioneAzione modalitaIdentificazione,
RegistroServiziManager registroServiziManager, RequestInfo requestInfo,
OpenSPCoop2Message message, OpenSPCoop2MessageSoapStreamReader soapStreamReader,
IProtocolFactory<?> protocolFactory,
boolean portaApplicativa,
WSDLValidatorConfig config) {
String azione = null;
try{
OperationFinder.checkIDServizioPerRiconoscimentoAzione(idServizio, modalitaIdentificazione);
org.openspcoop2.core.registry.constants.ServiceBinding serviceBinding = registroServiziManager.getServiceBinding(idServizio, requestInfo);
if(org.openspcoop2.core.registry.constants.ServiceBinding.SOAP.equals(serviceBinding)){
azione = OperationFinder.searchOperationByWsdlInRequestMessage(message, soapStreamReader, requestInfo, registroServiziManager, idServizio, log,
config);
}
else{
azione = OperationFinder.searchOperationByRestInRequestMessage(transportContext, requestInfo, registroServiziManager, idServizio, log,
protocolFactory, portaApplicativa);
}
}catch(Exception eForceRegistry){
log.debug("Riconoscimento forzato dell'azione non riuscito: "+eForceRegistry.getMessage(),eForceRegistry);
}
return azione;
}
public static String searchOperationByWsdlInRequestMessage(OpenSPCoop2Message msg, OpenSPCoop2MessageSoapStreamReader soapStreamReaderParam, RequestInfo requestInfo, RegistroServiziManager registroServiziReader,IDServizio idServizio,Logger log,
WSDLValidatorConfig config) throws DriverRegistroServiziException, DriverRegistroServiziNotFound{
return searchOperationByWsdl(true, msg, soapStreamReaderParam, requestInfo, registroServiziReader, idServizio, log,
config);
}
/**public static String searchOperationByWsdlInResponseMessage(OpenSPCoop2Message msg, RequestInfo requestInfo, RegistroServiziManager registroServiziReader,IDServizio idServizio,Logger log,
boolean rpcAcceptRootElementUnqualified) throws DriverRegistroServiziException, DriverRegistroServiziNotFound{
return searchOperationByWsdl(false, msg, requestInfo, registroServiziReader, idServizio, log,
rpcAcceptRootElementUnqualified);
}*/
private static String searchOperationByWsdl(boolean isRichiesta,OpenSPCoop2Message msg, OpenSPCoop2MessageSoapStreamReader soapStreamReaderParam, RequestInfo requestInfo, RegistroServiziManager registroServiziReader,IDServizio idServizio,Logger log,
WSDLValidatorConfig config) throws DriverRegistroServiziException, DriverRegistroServiziNotFound{
org.openspcoop2.core.registry.wsdl.AccordoServizioWrapper wrapper = registroServiziReader.getWsdlAccordoServizio(idServizio,InformationApiSource.SAFE_SPECIFIC_REGISTRY,false,false,requestInfo);
org.openspcoop2.core.registry.wsdl.AccordoServizioWrapperUtilities wrapperUtilities =
new org.openspcoop2.core.registry.wsdl.AccordoServizioWrapperUtilities(log,wrapper);
return wrapperUtilities.searchOperationName(isRichiesta, wrapper.getNomePortType(), msg, soapStreamReaderParam, config);
}
public static String searchOperationByRestInRequestMessage(TransportRequestContext transportContext, RequestInfo requestInfo, RegistroServiziManager registroServiziReader,IDServizio idServizio,Logger log,
IProtocolFactory<?> protocolFactory, boolean portaApplicativa) throws DriverRegistroServiziException, DriverRegistroServiziNotFound{
String normalizedInterfaceName = null;
try {
if(transportContext.getInterfaceName()!=null) {
PorteNamingUtils namingUtils = new PorteNamingUtils(protocolFactory);
if(portaApplicativa){
normalizedInterfaceName = namingUtils.normalizePA(transportContext.getInterfaceName());
}
else {
normalizedInterfaceName = namingUtils.normalizePD(transportContext.getInterfaceName());
}
}
}catch(Exception e) {
throw new DriverRegistroServiziException(e.getMessage(),e);
}
String path = RestUtilities.getUrlWithoutInterface(transportContext, normalizedInterfaceName);
HttpRequestMethod httpMethod = HttpRequestMethod.valueOf(transportContext.getRequestType());
try {
org.openspcoop2.core.registry.rest.AccordoServizioWrapper wrapper = registroServiziReader.getRestAccordoServizio(idServizio,InformationApiSource.SAFE_SPECIFIC_REGISTRY,false,false,false, requestInfo);
ApiOperation op = wrapper.getApi().findOperation(httpMethod, path);
if(op!=null) {
// Il path nella 'ApiOperation è normalizzato come sul registro
for (int i = 0; i < wrapper.getAccordoServizio().sizeResourceList(); i++) {
Resource r = wrapper.getAccordoServizio().getResource(i);
if(r.getMethod()==null) {
if(op.getHttpMethod()!=null) {
continue;
}
}
else {
if(op.getHttpMethod()==null) {
continue;
}
if(!r.getMethod().name().equals(op.getHttpMethod().name())){
continue;
}
}
if(r.getPath()==null) {
if(op.getPath()!=null) {
continue;
}
}
else {
String rPath = r.getPath();
String opPath = op.getPath();
if(rPath!=null && rPath.length()>1 && rPath.endsWith("/")) {
rPath = rPath.substring(0,rPath.length()-1);
}
if(opPath!=null && opPath.length()>1 && opPath.endsWith("/")) {
opPath = opPath.substring(0,opPath.length()-1);
}
if(rPath!=null && !rPath.equals(opPath)){
continue;
}
}
return r.getNome();
}
}
}catch(Exception e) {
throw new DriverRegistroServiziException(e.getMessage(),e);
}
return null;
}
private static String getActionByPlugin(Logger log,
IDServizio idServizio,
OpenSPCoop2Message message, OpenSPCoop2MessageSoapStreamReader soapStreamReader,
IProtocolFactory<?> protocolFactory) {
String azione = null;
try{
if(idServizio.getAzione()!=null){
// gia localizzata in precedenza
azione = idServizio.getAzione();
}
else{
OpenSPCoop2Message msgAnalizyProtocol = message;
if(message==null && soapStreamReader!=null) {
msgAnalizyProtocol=soapStreamReader.getHeader_OpenSPCoop2Message();
}
if(msgAnalizyProtocol!=null){
Busta busta = protocolFactory.createValidazioneSintattica(null).getBusta_senzaControlli(msgAnalizyProtocol);
if(busta!=null){
azione = busta.getAzione();
}
}
}
}catch(Exception eForcePlugin){
log.debug("Riconoscimento forzato dell'azione non riuscito: "+eForcePlugin.getMessage(),eForcePlugin);
}
return azione;
}
private static void checkIDServizioPerRiconoscimentoAzione(IDServizio idServizio, ModalitaIdentificazioneAzione modalitaIdentificazione) throws DriverConfigurazioneException{
String suffixError = " (necessari per procedere con la modalità di identificazione "+modalitaIdentificazione+" dell'azione)";
if(idServizio==null){
throw new DriverConfigurazioneException("Dati del servizio non trovati"+suffixError);
}
if(idServizio.getSoggettoErogatore()==null){
throw new DriverConfigurazioneException("Dati del soggetto erogatore del servizio non trovati"+suffixError);
}
if(idServizio.getSoggettoErogatore().getTipo()==null){
throw new DriverConfigurazioneException("Tipo soggetto erogatore del servizio non trovato"+suffixError);
}
if(idServizio.getSoggettoErogatore().getNome()==null){
throw new DriverConfigurazioneException("Nome soggetto erogatore del servizio non trovato"+suffixError);
}
if(idServizio.getTipo()==null){
throw new DriverConfigurazioneException("Tipo servizio non trovato"+suffixError);
}
if(idServizio.getNome()==null){
throw new DriverConfigurazioneException("Nome servizio non trovato"+suffixError);
}
if(idServizio.getVersione()==null){
throw new DriverConfigurazioneException("Versione servizio non trovata"+suffixError);
}
}
}