OpenSPCoop2Servlet.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.pdd.services.connector;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.openspcoop2.pdd.config.OpenSPCoop2Properties;
import org.openspcoop2.pdd.core.CostantiPdD;
import org.openspcoop2.pdd.core.byok.BYOKMapProperties;
import org.openspcoop2.pdd.logger.OpenSPCoop2Logger;
import org.openspcoop2.pdd.services.OpenSPCoop2Startup;
import org.openspcoop2.protocol.engine.ProtocolFactoryManager;
import org.openspcoop2.protocol.engine.URLProtocolContextImpl;
import org.openspcoop2.protocol.manifest.constants.Costanti;
import org.openspcoop2.protocol.sdk.IProtocolFactory;
import org.openspcoop2.protocol.sdk.constants.IDService;
import org.openspcoop2.protocol.sdk.state.FunctionContextsCustom;
import org.openspcoop2.protocol.sdk.state.URLProtocolContext;
import org.openspcoop2.utils.LoggerWrapperFactory;
import org.openspcoop2.utils.Semaphore;
import org.openspcoop2.utils.Utilities;
import org.openspcoop2.utils.transport.http.HttpRequestMethod;
import org.slf4j.Logger;
/**
* OpenSPCoop2Servlet
*
* @author Poli Andrea (apoli@link.it)
* @author $Author$
* @version $Rev$, $Date$
*/
@SuppressWarnings("serial")
public class OpenSPCoop2Servlet extends HttpServlet {
private static Logger logger = null;
private static synchronized Logger _getLogger() {
if ( logger == null ) {
logger = LoggerWrapperFactory.getLogger("govway.startup");
}
return logger;
}
private static Logger getLogger() {
if ( logger == null )
_getLogger();
return logger;
}
private static boolean checkSecrets = false;
private static final Semaphore semaphoreCheckSecrets = new Semaphore("GovWaySecrets");
private static void checkSecrets() {
if(!checkSecrets) {
initSecrets();
}
}
private static void initSecrets() {
semaphoreCheckSecrets.acquireThrowRuntime("initSecrets");
try {
if(!checkSecrets) {
BYOKMapProperties secretsProperties = BYOKMapProperties.getInstance();
if(secretsProperties!=null && secretsProperties.isExistsUnwrapPropertiesAfterGovWayStartup()) {
secretsProperties.setGovWayStarted(true);
try {
secretsProperties.initEnvironment();
String secretsConfig = OpenSPCoop2Properties.getInstance().getBYOKEnvSecretsConfig();
String msgInit = "Environment inizializzato con i secrets definiti nel file '"+secretsConfig+"' dopo il completamento dell'avvio di GovWay"+
"\n\tJavaProperties: "+secretsProperties.getJavaMap().keys()+
"\n\tEnvProperties: "+secretsProperties.getEnvMap().keys()+
"\n\tObfuscateMode: "+secretsProperties.getObfuscateModeDescription();
OpenSPCoop2Startup.logStartupInfo(msgInit);
} catch (Exception e) {
OpenSPCoop2Startup.logStartupError("Inizializzazione ambiente (secrets) non riuscita: "+e.getMessage(),e);
}
}
checkSecrets = true;
}
}finally {
semaphoreCheckSecrets.release("initSecrets");
}
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpRequestMethod m = null;
try {
m = HttpRequestMethod.valueOf(req.getMethod().toUpperCase());
}catch(Exception e) {
super.service(req, resp); // richiamo implementazione originale che genera errore: Method XXX is not defined in RFC 2068 and is not supported by the Servlet API
return;
}
switch (m) {
// Standard
case DELETE:
this.doDelete(req, resp);
break;
case GET:
this.doGet(req, resp);
break;
case HEAD:
this.doHead(req, resp);
break;
case OPTIONS:
this.doOptions(req, resp);
break;
case POST:
this.doPost(req, resp);
break;
case PUT:
this.doPut(req, resp);
break;
case TRACE:
this.doTrace(req, resp);
break;
// Additionals
case PATCH:
case LINK:
case UNLINK:
boolean enabled = true;
OpenSPCoop2Properties op2Properties = null;
try {
op2Properties = OpenSPCoop2Properties.getInstance();
}catch(Throwable t) {
//come default si lasciano abilitati
}
if(op2Properties!=null) {
if(HttpRequestMethod.PATCH.equals(m)) {
enabled = op2Properties.isServiceRequestHttpMethodPatchEnabled();
}
else if(HttpRequestMethod.LINK.equals(m)) {
enabled = op2Properties.isServiceRequestHttpMethodLinkEnabled();
}
else if(HttpRequestMethod.UNLINK.equals(m)) {
enabled = op2Properties.isServiceRequestHttpMethodUnlinkEnabled();
}
}
if(enabled) {
dispatch(req, resp, m);
}
else {
super.service(req, resp); // richiamo implementazione originale che genera errore: Method XXX is not defined in RFC 2068 and is not supported by the Servlet API
}
break;
default:
super.service(req, resp); // richiamo implementazione originale che genera errore: Method XXX is not defined in RFC 2068 and is not supported by the Servlet API
break;
}
}
@Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
dispatch(req, resp, HttpRequestMethod.DELETE);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
dispatch(req, resp, HttpRequestMethod.GET);
}
@Override
protected void doHead(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
dispatch(req, resp, HttpRequestMethod.HEAD);
}
@Override
protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
dispatch(req, resp, HttpRequestMethod.OPTIONS);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
dispatch(req, resp, HttpRequestMethod.POST);
}
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
dispatch(req, resp, HttpRequestMethod.PUT);
}
@Override
protected void doTrace(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
dispatch(req, resp, HttpRequestMethod.TRACE);
}
private void dispatch(HttpServletRequest req, HttpServletResponse res,HttpRequestMethod method) {
Logger logCore = OpenSPCoop2Logger.getLoggerOpenSPCoopCore();
Logger logOpenSPCoop2Servlet = getLogger();
OpenSPCoop2Properties op2Properties = null;
try {
if (!OpenSPCoop2Startup.initialize) {
// req.getContextPath()[/govway] req.getRequestURI()[/govway/check]
String contextPath = req.getContextPath();
String requestUri = req.getRequestURI();
if(requestUri!=null && contextPath!=null && requestUri.startsWith(contextPath) && requestUri.length()>contextPath.length()) {
String function = requestUri.substring(contextPath.length(), requestUri.length());
if(function.startsWith("/") && function.length()>1) {
function = function.substring(1);
}
if(function.equals(URLProtocolContext.Check_FUNCTION) || function.equals(URLProtocolContext.Proxy_FUNCTION)){
CheckStatoPdD.serializeNotInitializedResponse(res, (logCore!=null) ? logCore : logOpenSPCoop2Servlet);
return;
}
}
// Attendo inizializzazione
int max = CostantiPdD.WAIT_STARTUP_TIMEOUT_SECONDS;
int sleepCheck = CostantiPdD.WAIT_STARTUP_CHECK_INTERVAL_MS;
for (int i = 0; i < 5; i++) { // attendo 5 secondi la presenza delle proprietà
if(OpenSPCoop2Properties.getInstance()==null) {
Utilities.sleep(1000);
}
if(OpenSPCoop2Properties.getInstance()!=null) {
break;
}
}
if(OpenSPCoop2Properties.getInstance()!=null) {
max = OpenSPCoop2Properties.getInstance().getStartupRichiesteIngressoTimeoutSecondi();
sleepCheck = OpenSPCoop2Properties.getInstance().getStartupRichiesteIngressoCheckMs();
}
int maxMs = (max * 1000);
int actualMs = 0;
while(!OpenSPCoop2Startup.initialize && actualMs<maxMs) {
Utilities.sleep(sleepCheck);
actualMs = actualMs + sleepCheck;
}
if (!OpenSPCoop2Startup.initialize) {
// log su file core
StringBuilder bfLogError = new StringBuilder();
ConnectorUtils.generateErrorMessage(IDService.OPENSPCOOP2_SERVLET,method,req,bfLogError, "GovWay non inizializzato", true, false);
if(logCore!=null){
logCore.error(bfLogError.toString());
}
else{
logOpenSPCoop2Servlet.error(bfLogError.toString());
}
res.sendError(404,ConnectorUtils.generateError404Message(ConnectorUtils.getFullCodeGovWayNotInitialized(IDService.OPENSPCOOP2_SERVLET)));
return;
}
}
op2Properties = OpenSPCoop2Properties.getInstance();
boolean printCertificate = false;
FunctionContextsCustom customContexts = null;
if(op2Properties!=null) {
printCertificate = op2Properties.isPrintInfoCertificate();
customContexts = op2Properties.getCustomContexts();
}
URLProtocolContext protocolContext = new URLProtocolContextImpl(req, logCore, printCertificate, customContexts);
String function = protocolContext.getFunction();
IDService idServiceCustom = protocolContext.getIdServiceCustom();
IProtocolFactory<?> pf = ProtocolFactoryManager.getInstance().getProtocolFactoryByServletContext(protocolContext.getProtocolWebContext());
if(pf==null){
if(!Costanti.CONTEXT_EMPTY.equals(protocolContext.getProtocolWebContext()))
throw new Exception("Non risulta registrato un protocollo con contesto ["+protocolContext.getProtocolWebContext()+"]");
else
throw new Exception("Non risulta registrato un protocollo con contesto speciale 'vuoto'");
}
if(
(function.equals(URLProtocolContext.PD_FUNCTION) && op2Properties.isEnabledFunctionPD())
||
(idServiceCustom!=null && IDService.PORTA_DELEGATA.equals(idServiceCustom))
){
checkSecrets();
RicezioneContenutiApplicativiConnector r = new RicezioneContenutiApplicativiConnector();
r.doEngine(ConnectorUtils.getRequestInfo(pf, protocolContext), req, res, method);
}
else if(
(function.equals(URLProtocolContext.PDtoSOAP_FUNCTION) && op2Properties.isEnabledFunctionPDtoSOAP())
||
(idServiceCustom!=null && IDService.PORTA_DELEGATA_XML_TO_SOAP.equals(idServiceCustom))
){
checkSecrets();
RicezioneContenutiApplicativiHTTPtoSOAPConnector r = new RicezioneContenutiApplicativiHTTPtoSOAPConnector();
r.doEngine(ConnectorUtils.getRequestInfo(pf, protocolContext), req, res, method);
}
else if(
(function.equals(URLProtocolContext.PA_FUNCTION) && op2Properties.isEnabledFunctionPA())
||
(idServiceCustom!=null && IDService.PORTA_APPLICATIVA.equals(idServiceCustom))
){
checkSecrets();
RicezioneBusteConnector r = new RicezioneBusteConnector();
r.doEngine(ConnectorUtils.getRequestInfo(pf, protocolContext), req, res, method);
}
else if(function.equals(URLProtocolContext.IntegrationManager_FUNCTION) || (idServiceCustom!=null && IDService.INTEGRATION_MANAGER_SOAP.equals(idServiceCustom))){
checkSecrets();
if(op2Properties!=null && op2Properties.isIntegrationManagerEnabled()==false) {
throw new Exception("Service ["+function+"] not active");
}
boolean wsdl = false;
if(HttpRequestMethod.GET.equals(method)){
Enumeration<?> parameters = req.getParameterNames();
while(parameters.hasMoreElements()){
String key = (String) parameters.nextElement();
String value = req.getParameter(key);
if("wsdl".equalsIgnoreCase(key) && (value==null || "".equals(value)) ){
// richiesta del wsdl
if(op2Properties!=null && op2Properties.isGenerazioneWsdlIntegrationManagerEnabled()==false){
res.sendError(404, ConnectorUtils.generateError404Message(ConnectorUtils.getFullCodeWsdlUnsupported(IDService.INTEGRATION_MANAGER_SOAP)));
return;
}
else{
wsdl = true;
break;
}
}
}
}
if(!HttpRequestMethod.POST.equals(method) && !wsdl){
// messaggio di errore
boolean errore404 = false;
if(op2Properties!=null && !op2Properties.isGenerazioneErroreHttpMethodUnsupportedIntegrationManagerEnabled()){
errore404 = true;
}
if(errore404){
res.sendError(404,ConnectorUtils.generateError404Message(ConnectorUtils.getFullCodeHttpMethodNotSupported(IDService.INTEGRATION_MANAGER_SOAP, method)));
return;
}
else{
res.setStatus(500);
ConnectorUtils.generateErrorMessage(IDService.INTEGRATION_MANAGER_SOAP, method, req, res, ConnectorUtils.getMessageHttpMethodNotSupported(method), false, true);
try{
res.getOutputStream().flush();
}catch(Exception eClose){
// ignore
}
try{
res.getOutputStream().close();
}catch(Exception eClose){
// ignore
}
return;
}
}
// Dispatching al servizio di IntegrationManager implementato tramite CXF
String serviceIM = protocolContext.getFunctionParameters();
if(URLProtocolContext.IntegrationManager_SERVICE_PD_GOVWAY.equals(serviceIM) ||
(URLProtocolContext.IntegrationManager_SERVICE_PD_GOVWAY+"/").equals(serviceIM)) {
serviceIM = URLProtocolContext.IntegrationManager_SERVICE_PD;
}
String forwardUrl = "/"+URLProtocolContext.IntegrationManager_ENGINE+"/"+serviceIM;
req.setAttribute(org.openspcoop2.core.constants.Costanti.PROTOCOL_NAME.getValue(), protocolContext.getProtocolName());
req.setAttribute(org.openspcoop2.core.constants.Costanti.PROTOCOL_WEB_CONTEXT.getValue(), protocolContext.getProtocolWebContext());
req.setAttribute(org.openspcoop2.core.constants.Costanti.INTEGRATION_MANAGER_ENGINE_AUTHORIZED.getValue(), true);
RequestDispatcher dispatcher = req.getRequestDispatcher(forwardUrl);
dispatcher.forward(req, res);
}
else if(function.equals(URLProtocolContext.Check_FUNCTION)){
if(HttpRequestMethod.GET.equals(method)==false){
// messaggio di errore
boolean errore404 = false;
if(op2Properties!=null && !op2Properties.isGenerazioneErroreHttpMethodUnsupportedCheckEnabled()){
errore404 = true;
}
if(errore404){
res.sendError(404,ConnectorUtils.generateError404Message(ConnectorUtils.getFullCodeHttpMethodNotSupported(IDService.CHECK_PDD, method)));
return;
}
else{
res.setStatus(500);
ConnectorUtils.generateErrorMessage(IDService.CHECK_PDD,method,req,res, ConnectorUtils.getMessageHttpMethodNotSupported(method), false, true);
try{
res.getOutputStream().flush();
}catch(Exception eClose){
// ignore
}
try{
res.getOutputStream().close();
}catch(Exception eClose){
// ignore
}
return;
}
}
// Dispatching al servizio
CheckStatoPdD checkStatoPdD = new CheckStatoPdD();
req.setAttribute(org.openspcoop2.core.constants.Costanti.PROTOCOL_NAME.getValue(), protocolContext.getProtocolName());
checkStatoPdD.doGet(req, res);
}
else if(function.equals(URLProtocolContext.Proxy_FUNCTION)){
if(op2Properties!=null && !op2Properties.isProxyReadJMXResourcesEnabled()) {
throw new Exception("Service ["+function+"] not supported");
}
if(HttpRequestMethod.GET.equals(method)==false){
// messaggio di errore
boolean errore404 = false;
if(op2Properties!=null && !op2Properties.isGenerazioneErroreHttpMethodUnsupportedProxyEnabled()){
errore404 = true;
}
if(errore404){
res.sendError(404,ConnectorUtils.generateError404Message(ConnectorUtils.getFullCodeHttpMethodNotSupported(IDService.PROXY, method)));
return;
}
else{
res.setStatus(500);
ConnectorUtils.generateErrorMessage(IDService.PROXY,method,req,res, ConnectorUtils.getMessageHttpMethodNotSupported(method), false, true);
try{
res.getOutputStream().flush();
}catch(Exception eClose){
// ignore
}
try{
res.getOutputStream().close();
}catch(Exception eClose){
// ignore
}
return;
}
}
// Dispatching al servizio
Proxy proxy = new Proxy();
req.setAttribute(org.openspcoop2.core.constants.Costanti.PROTOCOL_NAME.getValue(), protocolContext.getProtocolName());
proxy.doGet(req, res);
}
else{
throw new Exception("Service ["+function+"] not supported");
}
} catch (Exception e) {
StringBuilder bf = new StringBuilder();
bf.append("RemoteAddr["+req.getRemoteAddr()+"] ");
bf.append("RemoteHost["+req.getRemoteHost()+"] ");
bf.append("RemotePort["+req.getRemotePort()+"] ");
bf.append("RemoteUser["+req.getRemoteUser()+"] ");
bf.append("LocalAddr["+req.getLocalAddr()+"] ");
bf.append("LocalHost["+req.getLocalName()+"] ");
bf.append("LocalPort["+req.getLocalPort()+"] ");
bf.append("ServerName["+req.getServerName()+"] ");
bf.append("ServerPort["+req.getServerPort()+"] ");
if(logCore!=null){
logCore.error(e.getMessage(),e);
logCore.error("Detail: "+bf.toString());
}
else{
logOpenSPCoop2Servlet.error(e.getMessage(),e);
logOpenSPCoop2Servlet.error("Detail: "+bf.toString());
}
// log su file core
StringBuilder bfLogError = new StringBuilder();
try {
ConnectorUtils.generateErrorMessage(IDService.OPENSPCOOP2_SERVLET,method,req,bfLogError, e.getMessage(), true, false);
if(logCore!=null){
logCore.error(bfLogError.toString());
}
else{
logOpenSPCoop2Servlet.error(bfLogError.toString());
}
}catch(Throwable t) {
if(logCore!=null){
logCore.error("generateErrorMessage log failed: "+t.getMessage(),t);
}
else{
logOpenSPCoop2Servlet.error("generateErrorMessage log failed: "+t.getMessage(),t);
}
}
// messaggio di errore
boolean errore404 = true;
if(op2Properties!=null && op2Properties.isGenerazioneErroreProtocolloNonSupportato()){
errore404 = false;
}
if(errore404){
try {
res.sendError(404,ConnectorUtils.generateError404Message(ConnectorUtils.getFullCodeProtocolUnsupported(IDService.OPENSPCOOP2_SERVLET)));
}catch(Throwable t) {
if(logCore!=null){
logCore.error("sendError404 failed: "+t.getMessage(),t);
}
else{
logOpenSPCoop2Servlet.error("sendError404 failed: "+t.getMessage(),t);
}
}
}
else{
res.setStatus(500);
try {
ConnectorUtils.generateErrorMessage(IDService.OPENSPCOOP2_SERVLET,method,req,res, e.getMessage(), true, true);
}catch(Throwable t) {
if(logCore!=null){
logCore.error("generateErrorMessage failed: "+t.getMessage(),t);
}
else{
logOpenSPCoop2Servlet.error("generateErrorMessage failed: "+t.getMessage(),t);
}
}
try{
res.getOutputStream().flush();
}catch(Throwable eClose){
// ignore
}
try{
res.getOutputStream().close();
}catch(Throwable eClose){
// ignore
}
}
}
}
}