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:
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
NomeDescrizioneTipoObbligatorio
portaDelegataIDL'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}. * StringSi, a meno che non venga specificato il parametro sessionBeanID oppure serviceHttpURL *
sessionBeanIDL'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}. * StringSi, a meno che non venga specificato il parametro portaDelegataID oppure serviceHttpURL *
serviceHttpURLL'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}.StringSi, a meno che non venga specificato il parametro portaDelegataID oppure sessionBeanID *
inputStylesheetIl 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}.StringSi, a meno che non venga specificato il parametro portaDelegataID
* * @author Federico Lelli, Stefano Ricciarelli, Fabrizio Agostinelli, Filippo Fornari, Enrico Testa, Simone * Casciaroli * @cvsauthor $Author: flelli $ * @cvsdate $Date: 2008/03/18 11:20:25 $ * @cvsrevision $Revision: 1.24 $ */ public abstract class AbstractServlet extends AbstractGeneralServlet { /** Il nome del parametro che definisce l'id della porta delegata da utilizzare. */ public static final String PNAME_PORTA_DELEGATA_ID = "portaDelegataID"; /** Il nome del parametro che definisce l'id del session bean da utilizzare come Servizio. */ public static final String PNAME_SESSION_BEAN_ID = "sessionBeanID"; /** Il nome del parametro che definisce l'URL della servlet remota da invocare. */ public static final String PNAME_SERVICE_HTTP_URL = "serviceHttpURL"; /** * Il nome del parametro che definisce lo stylesheet XSL da utilizzare per formattare le richieste da inviare al * servizio. */ public static final String PNAME_INPUT_STYLESHEET = "inputStylesheet"; /** L'istanza dello stylesheet riutilizzabile in input. */ protected Templates inputStylesheetTemplate = null; /** L'ID della home interface del bean utilizzato come servizio. */ private String beanID = null; /** * Indica la modalita' di comunicazione da utilizzare per il colloquio con il servizio . Se 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); } }