package it.corenet.j2ee.servlet;
import java.io.Reader;
import javax.security.auth.Subject;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Templates;
import org.w3c.dom.Document;
import it.corenet.j2ee.common.LogUtils;
import it.corenet.j2ee.common.xml.BadXmlDocumentException;
import it.corenet.j2ee.common.xml.InvalidXmlDocumentException;
import it.corenet.j2ee.messages.Message;
/**
* Classe di base per l'implementazione di una applicazione servlet. Questa classe fornisce i servizi di base per le
* comunicazioni con i servizi di back office.
* Le servlet che estendono questa non devono preoccuparsi di gestire le comunicazioni con i servizi che possono
* avvenire in tre modi: a) per mezzo delle Porte Di Dominio; b) per mezzo di comunicazioni RMI/IIOP generiche. Nel
* primo caso il Servizio viene visto come Porta Applicativa (e la servlet impiega una Porta Delegata per accedervi),
* mentre nel secondo viene acceduto come EJB (Stateless Session Bean). Per soddisfare questa dualita' di canali di
* accesso il Servizio deve essere un EJB che espone una home interface di tipo {@link
* it.corenet.j2ee.servizi.ServizioRemoteHome ServizioRemoteHome}
(o una sottoclasse) e di conseguenza una remote
* interface di tipo {@link it.corenet.j2ee.servizi.ServizioRemote ServizioRemote}
(o una sottoclasse). c)
* per mezzo di una connessione HTTP con una servlet che espone dei servizi.
* La servlet determina se utilizzare un metodo di comunicazione o un altro a seconda che sia stato definito l'uno o
* l'altro parametro fra portaDelegataID
e sessionBeanID
(vedi tabella sottostante).
* Le servlet che estendono da questa devono definire, nel deployment descriptor, i seguenti parametri:
*
*
Nome | *Descrizione | *Tipo | *Obbligatorio | *
portaDelegataID |
* L'identificativo della porta delegata da utilizzare per le comunicazioni con il servizio associato. Il nome
* del parametro, per uso applicativo, e' definito nella costante {@link #PNAME_PORTA_DELEGATA_ID} .
* |
* String |
* Si, a meno che non venga specificato il parametro sessionBeanID oppure serviceHttpURL
* |
*
sessionBeanID |
* L'identificativo del session bean da utilizzare per le comunicazioni con il servizio . Questo ID server per
* fare il lookup sul JNDI context per recuperare la home interface del bean. La home interface deve essere una
* {@link it.corenet.j2ee.servizi.ServizioRemoteHome ServizioRemoteHome} o una sottoclasse. Il nome
* del parametro, per uso applicativo, e' definito nella costante {@link #PNAME_SESSION_BEAN_ID} .
* |
* String |
* Si, a meno che non venga specificato il parametro portaDelegataID oppure serviceHttpURL
* |
*
serviceHttpURL |
* L'URL della servlet remota da utilizzare per le comunicazioni con il servizio. Il nome del parametro, per uso
* applicativo, e' definito nella costante {@link #PNAME_SERVICE_HTTP_URL} . |
* String |
* Si, a meno che non venga specificato il parametro portaDelegataID oppure sessionBeanID
* |
*
inputStylesheet |
* Il percorso ella risorsa da utilizzare come stylesheet XSL per la formattazione delle richieste da inviare al
* servizio Il nome del parametro, per uso applicativo, e' definito nella costante {@link
* #PNAME_INPUT_STYLESHEET} . |
* String |
* Si, a meno che non venga specificato il parametro portaDelegataID |
*
EJB
deve
* essere utilizzato il metodo EJB (RMI/IIOP), se PDD
deve essere utilizzata la Porta Delegata,se
* HTTP
deve essere utilizzata la Connessione HTTP, se null
non e' stato possibile
* determinare il valore del parametro o la lettura dello stesso deve ancora avvenire.
*/
private String communicationMode = null;
/** L'ID della porta delegata impiegato per inviare richieste e ricevere risposte attraverso le porte di dominio. */
private String portaDelegataID = null;
/** L'URL della servlet remota da invocare per i servizi. */
private String serviceHttpURL = null;
/**
* Provvede alla configurazione della servlet. Le servlet che ereditano da questa possono fare l'override di questo
* metodo ma devo sempre invocare super.init(config)
.
*
* @param config la configurazione della servlet
*
* @throws ServletException se la configurazione non e' corretta o manca di dati essenziali.
*/
public void init(ServletConfig config)
throws ServletException
{
super.init(config);
initCommunicationMode(config);
if (communicationMode.equals(ServletToolBox.EJB_COMMUNICATION_MODE_NAME))
{
initEJB(config);
}
else if (communicationMode.equals(ServletToolBox.PDD_COMMUNICATION_MODE_NAME))
{
initPortaDelegata(config);
}
else if (communicationMode.equals(ServletToolBox.HTTP_COMMUNICATION_MODE_NAME))
{
initServletURL(config);
}
initStylesheets(config);
}
/**
* Restituisce la modalit� di comunicazione impostata per la chiamata dei servizi infrastrutturali in fase di
* configurazione.
*
* @return EJB
se in modalit� EJB, false
se attraverso Porta Di Dominio.
*/
protected String getCommunicationMode()
{
return communicationMode;
}
/**
* Restituisce l'identificativo del servizio da richiamare secondo quanto impostato nel file di configurazione della
* servlet.
*
* @return identificativo del servizio da richiamare.
*/
protected String getServiceId()
{
if (communicationMode.equals(ServletToolBox.EJB_COMMUNICATION_MODE_NAME))
{
return beanID;
}
else if (communicationMode.equals(ServletToolBox.PDD_COMMUNICATION_MODE_NAME))
{
return portaDelegataID;
}
else if (communicationMode.equals(ServletToolBox.HTTP_COMMUNICATION_MODE_NAME))
{
return serviceHttpURL;
}
else
{
return null;
}
}
/**
* Carica lo stylesheet e lo precompila.
*
* @param config la configurazione della servlet
*
* @throws ServletException se la configurazione non e' corretta o manca di dati essenziali.
*/
protected void initStylesheets(ServletConfig config)
throws ServletException
{
super.initStylesheets(config);
String inputStylesheet = config.getInitParameter(PNAME_INPUT_STYLESHEET);
if (inputStylesheet != null)
{
inputStylesheetTemplate = compileStylesheet(config, inputStylesheet);
}
else
{
logger.debug("Nessuno stylesheet di input configurato");
}
}
/**
* Invia la richiesta al servizio integrato e riceve la risposta prodotta dallo stesso.
*
* @param reqDocument il documento XML che modella la richiesta
*
* @return il documento XML che contiene la risposta
*
* @throws ServletException se si incontra una eccezione bloccante
* @throws BadXmlDocumentException sollevata nel caso il contenuto del messaggio di risposta non rappresenti
* un documento xml ben formato.
* @throws InvalidXmlDocumentException sollevata nel caso il contenuto del messaggio di risposta, pur se attinente
* alle specifiche xml, non rappresenti un documento xml valido rispetto allo
* schema xml di validazione.
*/
protected Document performRequest(Document reqDocument)
throws ServletException, BadXmlDocumentException, InvalidXmlDocumentException
{
return performRequest(reqDocument, null);
}
/**
* Invia il messaggio al servizio infrastrutturale e riceve la risposta prodotta dallo stesso.
*
* @param reqMsg il messaggio che modella la richiesta
*
* @return il messaggio che contiene la risposta
*
* @throws ServletException se si incontra una eccezione bloccante
*/
protected Message performRequest(Message reqMsg)
throws ServletException
{
return performRequest(reqMsg, this.getServiceId(), communicationMode);
}
/**
* Invia la richiesta al servizio integrato e riceve la risposta prodotta dallo stesso.
*
* @param reqDocument il documento XML che modella la richiesta
* @param subject il subject cui appartiene la richiesta.
*
* @return il documento XML che contiene la risposta
*
* @throws ServletException se si incontra una eccezione bloccante
* @throws BadXmlDocumentException sollevata nel caso il contenuto del messaggio di risposta non rappresenti
* un documento xml ben formato.
* @throws InvalidXmlDocumentException sollevata nel caso il contenuto del messaggio di risposta, pur se attinente
* alle specifiche xml, non rappresenti un documento xml valido rispetto allo
* schema xml di validazione.
*/
protected Document performRequest(Document reqDocument, Subject subject)
throws ServletException, BadXmlDocumentException, InvalidXmlDocumentException
{
return performRequest(reqDocument, this.getServiceId(), communicationMode);
}
/**
* Invia la richiesta al servizio integrato e riceve la risposta prodotta dallo stesso. Questo metodo agisce, per
* quanto possibile, in modalita' stream
*
* @param reqReader il reader da cui leggere l'XML di richiesta
*
* @return il reader da cui leggere l'XML di risposta
*
* @throws ServletException se si incontra una eccezione bloccante
* @throws BadXmlDocumentException sollevata nel caso il contenuto del messaggio di risposta non rappresenti
* un documento xml ben formato.
* @throws InvalidXmlDocumentException sollevata nel caso il contenuto del messaggio di risposta, pur se attinente
* alle specifiche xml, non rappresenti un documento xml valido rispetto allo
* schema xml di validazione.
*/
protected Reader performRequestUseStream(Reader reqReader)
throws ServletException, BadXmlDocumentException, InvalidXmlDocumentException
{
return performRequestUseStream(reqReader, null);
}
/**
* Invia la richiesta al servizio integrato e riceve la risposta prodotta dallo stesso. Questo metodo agisce, per
* quanto possibile, in modalita' stream
*
* @param reqReader il reader da cui leggere l'XML di richiesta
* @param subject il subject cui appartiene la richiesta.
*
* @return il reader da cui leggere l'XML di risposta
*
* @throws ServletException se si incontra una eccezione bloccante
* @throws BadXmlDocumentException sollevata nel caso il contenuto del messaggio di risposta non rappresenti
* un documento xml ben formato.
* @throws InvalidXmlDocumentException sollevata nel caso il contenuto del messaggio di risposta, pur se attinente
* alle specifiche xml, non rappresenti un documento xml valido rispetto allo
* schema xml di validazione.
*/
protected Reader performRequestUseStream(Reader reqReader, Subject subject)
throws ServletException, BadXmlDocumentException, InvalidXmlDocumentException
{
return performRequestUseStream(reqReader, this.getServiceId(), communicationMode, subject);
}
/**
* Processa la richiesta e produce un documento XML da passare al servizio.
*
* @param source la richiesta da processare
*
* @return il documento di richiesta da inviare al servizio
*
* @throws ServletException in caso di errore
*
* @deprecated Questo metodo e' stato lasciato per compatibilita', ma il suo uso e' limitato alla creazione di un
* elemento con rootName XML_ELEMENT_REQUEST_ROOT
*/
protected Document transformDataRequest(HttpServletRequest source)
throws ServletException
{
logger.debug("Richiesta con parametri. Produzione della richiesta dati al servizio.");
return transformDataRequest(source, XML_ELEMENT_REQUEST_ROOT);
}
/**
* Processa la richiesta e produce un documento XML da passare al servizio.
*
* @param source la richiesta da processare
* @param rootName il nome dell'elemento radice
*
* @return il documento di richiesta da inviare al servizio
*
* @throws ServletException in caso di errore
*/
protected Document transformDataRequest(HttpServletRequest source, String rootName)
throws ServletException
{
try
{
Document intermediateDoc = ServletToolBox.createRequestDocument(source, rootName);
LogUtils.logXMLDocument("Documento intermedio", intermediateDoc, logger);
Document serviceReq = ServletToolBox.transformDataRequest(source, rootName,
((rootName != XML_ELEMENT_PRECOMPILAZIONE_ROOT) ? inputStylesheetTemplate : null));
LogUtils.logXMLDocument("Richiesta Servizio", serviceReq, logger);
return serviceReq;
}
catch (ServletException se)
{
logger.error("ECCEZIONE COMPLETA: " + LogUtils.getCompleteExceptionString(se));
throw se;
}
catch (ParserConfigurationException parsEx)
{
logger.error("ECCEZIONE COMPLETA: " + LogUtils.getCompleteExceptionString(parsEx));
throw new ServletException(parsEx);
}
}
/**
* Processa la richiesta e produce un documento XML da passare al servizio.
*
* @param source la richiesta da processare
*
* @return il reader da cui ottenere il documento di richiesta da inviare al servizio
*
* @throws ServletException in caso di errore
*
* @deprecated Questo metodo e' stato lasciato per compatibilita', ma il suo uso e' limitato alla creazione di un
* elemento con rootName XML_ELEMENT_REQUEST_ROOT
*/
protected Reader transformDataRequestUseStream(HttpServletRequest source)
throws ServletException
{
logger.debug("Richiesta con parametri. Produzione della richiesta dati al servizio.");
return transformDataRequestUseStream(source, XML_ELEMENT_REQUEST_ROOT);
}
/**
* Processa la richiesta e produce un documento XML da passare al servizio.
*
* @param source la richiesta da processare
* @param rootName il nome dell'elemento radice
*
* @return il reader da cui ottenere il documento di richiesta da inviare al servizio
*
* @throws ServletException in caso di errore
*/
protected Reader transformDataRequestUseStream(HttpServletRequest source, String rootName)
throws ServletException
{
try
{
Document intermediateDoc = ServletToolBox.createRequestDocument(source, rootName);
LogUtils.logXMLDocument("Documento intermedio", intermediateDoc, logger);
return ServletToolBox.transformDataRequestUseStream(source, rootName,
((rootName != XML_ELEMENT_PRECOMPILAZIONE_ROOT) ? inputStylesheetTemplate : null));
}
catch (ServletException se)
{
logger.error("ECCEZIONE COMPLETA: " + LogUtils.getCompleteExceptionString(se));
throw se;
}
catch (ParserConfigurationException parsEx)
{
logger.error("ECCEZIONE COMPLETA: " + LogUtils.getCompleteExceptionString(parsEx));
throw new ServletException(parsEx);
}
}
/**
* Determina la modalita' di comunicazione da impiegare per il colloquio con il servizio .
*
* @param config la configurazione della servlet
*
* @throws ServletException se la configurazione non e' corretta o manca di dati essenziali.
*/
private void initCommunicationMode(ServletConfig config)
throws ServletException
{
if (config.getInitParameter(PNAME_SESSION_BEAN_ID) != null)
{
communicationMode = ServletToolBox.EJB_COMMUNICATION_MODE_NAME;
logger.debug("Il servizio viene utilizzato come session bean");
}
else if (config.getInitParameter(PNAME_PORTA_DELEGATA_ID) != null)
{
communicationMode = ServletToolBox.PDD_COMMUNICATION_MODE_NAME;
logger.debug("Il servizio viene utilizzato come porta applicativa");
}
else if (config.getInitParameter(PNAME_SERVICE_HTTP_URL) != null)
{
communicationMode = ServletToolBox.HTTP_COMMUNICATION_MODE_NAME;
logger.debug("Il servizio viene utilizzato come chiamata HTTP ad una servlet remota");
}
else
{
throw new ServletException(
"Non e' stato specificato alcun metodo di comunicazione con il servizio. Specificare uno dei parametri '" +
PNAME_SESSION_BEAN_ID + "' o '" + PNAME_PORTA_DELEGATA_ID + "' o '" + PNAME_SERVICE_HTTP_URL + "'");
}
}
/**
* Recupera il session bean che rappresenta il servizio .
*
* @param config la configurazione della servlet
*
* @throws ServletException se la configurazione non e' corretta o manca di dati essenziali.
*/
private void initEJB(ServletConfig config)
throws ServletException
{
beanID = config.getInitParameter(PNAME_SESSION_BEAN_ID);
logger.debug("Il bean utilizzato e' " + beanID);
if ((beanID == null) || ("".equals(beanID)))
{
throw new ServletException(
"Impossibile determinare l'id del session bean dalla configurazione corrente. Definire il parametro '" +
PNAME_SESSION_BEAN_ID + "'");
}
}
/**
* Inizializza la Porta Delegata da utilizzare per le comunicazioni con il servizio .
*
* @param config la configurazione della servlet
*
* @throws ServletException se la configurazione non e' corretta o manca di dati essenziali.
*/
private void initPortaDelegata(ServletConfig config)
throws ServletException
{
portaDelegataID = config.getInitParameter(PNAME_PORTA_DELEGATA_ID);
logger.debug("La porta applicativa utilizzata e' " + portaDelegataID);
if ((portaDelegataID == null) || ("".equals(portaDelegataID)))
{
throw new ServletException(
"Impossibile determinare l'id della porta delegata dalla configurazione corrente. Definire il parametro '" +
PNAME_PORTA_DELEGATA_ID + "'");
}
logger.debug("initPortaDelegata terminato correttamente per la porta" + portaDelegataID);
}
/**
* Inizializza l'URL della servlet da utilizzare per le comunicazioni con il servizio .
*
* @param config la configurazione della servlet
*
* @throws ServletException se la configurazione non e' corretta o manca di dati essenziali.
*/
private void initServletURL(ServletConfig config)
throws ServletException
{
serviceHttpURL = config.getInitParameter(PNAME_SERVICE_HTTP_URL);
logger.debug("L'URL utilizzato e' " + serviceHttpURL);
if ((serviceHttpURL == null) || ("".equals(serviceHttpURL)))
{
throw new ServletException(
"Impossibile determinare l'URL della servlet remota dalla configurazione corrente. Definire il parametro '" +
PNAME_SERVICE_HTTP_URL + "'");
}
logger.debug("initServletURL terminato correttamente per l'URL" + serviceHttpURL);
}
}