2010-09-18 13 views
5

Tengo una aplicación web escrita usando Tomcat 6 y estoy tratando de hacerlo funcionar con Tomcat 7. Durante su inicio, la aplicación, además de otras cosas, registra su componente de servicio web en algún directorio remoto. Para esto, necesita proporcionar su propia URL. El (un poco ingenua) siguiendo el procedimiento debe devolver el URL de servicio web:Obtener URL de servlet completo durante el inicio bajo Tomcat 7

import org.apache.catalina.ServerFactory; 
import org.apache.catalina.connector.Connector; 
. 
. 
. 
private String getWsUrl(ServletContext context) 
      throws UnknownHostException, MalformedURLException { 
    String host = java.net.InetAddress.getLocalHost().getCanonicalHostName(); 
    int port = -1; 
    for (Connector c : ServerFactory.getServer().findServices()[0].findConnectors()) { 
     if (c.getProtocol().contains("HTTP")) { 
      port = c.getPort(); 
      break; 
     } 
    } 
    URL wsURL = new URL("http", host, port, context.getContextPath() 
       + C.WEB_SERVICE_PATH /* this is just a constant string */); 
    return wsURL.toString(); 
} 

La parte ServerFactory.getServer() se resultó ser problemática: no hay clase org.apache.catalina.ServerFactory en Tomcat 7. ¿Alguna sugerencia sobre cómo volver a escribir esto para Tomcat 7 ? También me gustaría tener más código portátil, no específico para tomcat.

Respuesta

0

Nunca lo he usado, y probablemente no devuelva una URL con el nombre de host y la dirección, pero ¿hay alguna posibilidad de que ServletContext.getResource("/") haga lo que quiera? Sé que está destinado a acceder a un recurso internamente por el servlet, pero nunca se sabe.

+0

Devuelve un sistema de archivo de disco ** ** basado 'URL' que apunta a la raíz del contenido de la web pública. Así que no, esto no hace absolutamente lo que el OP quiere :) – BalusC

+0

Bien. Los documentos API no especifican qué tipo de URL devuelve, y no tuve tiempo para probarlo. Gracias por verificar eso. –

3

Me enfrenté al mismo problema: necesitaba saber el número de puerto para construir una URL para una instancia de Tomcat en particular, el número de puerto puede variar (porque ejecuto varias instancias para probar) y a partir de Tomcat 7 ServerFactory se ha ido lejos.

Escribí el siguiente código para buscar y analizar el archivo server.xml de Tomcat. No analiza mucho, solo obtiene los valores HTTP "puerto" y "redirecciónPuerto". Depende de las propiedades del sistema "catalina.home" o "catalina.base", que deberían existir en cualquier instancia de Tomcat en ejecución. La belleza es que no depende de ninguna clase de Tomcat, y usa el analizador XML de la JVM.

Espero que esto ayude.

public final class TomcatConfigUtil { 

private static final String CONFIG_FILE_PATH = "conf/server.xml"; 

private static Map<String, String> properties = null; 

// No instances, please. 
private TomcatConfigUtil() { } 


/** 
* Get the configuration as a map of name/value pairs, or throw an exception if it wasn't found. 
* All values are returned as Strings. 
* <ul> 
* <li> httpPort - the HTTP port</li> 
* <li> httpRedirectPort - the HTTP redirect port (which seems to be the SSL port) </li> 
* </ul> 
* @exception FileNotFoundException if the configuration file wasn't found 
* @exception IOException if there was a problem reading the configuration file 
* @exception SAXException if there was a problem parsing the configuration file 
*/ 
public static synchronized Map<String, String> getConfig() throws FileNotFoundException, IOException, SAXException { 

    if (properties != null) { 

     return properties; 
    } 

    final File serverConfigFile = findServerConfigFile(); 
    if (serverConfigFile == null) { 

     throw new FileNotFoundException("Couldn't find the configuration file."); 
    } 

    final Map<String, String> tmpProperties = new HashMap<String, String>(); 

    // Content-handler does the actual parsing. 
    final ServerConfigContentHandler contentHandler = new ServerConfigContentHandler(tmpProperties); 
    final XMLReader xmlReader = XMLReaderFactory.createXMLReader(); 
    xmlReader.setContentHandler(contentHandler); 

    // Pass the config file as the input source for parsing. 
    final FileReader fileReader = new FileReader(serverConfigFile); 
    xmlReader.parse(new InputSource(fileReader)); 
    fileReader.close(); 

    return (properties = Collections.unmodifiableMap(tmpProperties)); 
} 


private static File findServerConfigFile() { 

    if (System.getProperty("catalina.home") != null) { 

     final File file = new File(System.getProperty("catalina.home"), CONFIG_FILE_PATH); 
     if (file.isFile()) { 

      return file; 
     } 
    } 

    if (System.getProperty("catalina.base") != null) { 

     final File file = new File(System.getProperty("catalina.base"), CONFIG_FILE_PATH); 
     if (file.isFile()) { 

      return file; 
     } 
    } 

    return null; 
} 


/** 
* ContentHandler implementation for the XML parser. 
*/ 
private static class ServerConfigContentHandler implements ContentHandler { 

    private final Map<String, String> map; 
    private boolean inServerElement; 
    private boolean inCatalinaServiceElement; 


    private ServerConfigContentHandler(final Map<String, String> map) { 

     this.map = map; 
    } 

    @Override 
    public void startDocument() throws SAXException { 

     this.inServerElement = false; 
     this.inCatalinaServiceElement = false; 
    } 

    @Override 
    public void startElement(final String uri, final String localName, final String qName, final Attributes atts) throws SAXException { 

     if (!this.inServerElement && "Server".equals(localName)) { 

      this.inServerElement = true; 
     } 
     else if (this.inServerElement && "Service".equals(localName) && "Catalina".equals(atts.getValue("name"))) { 

      this.inCatalinaServiceElement = true; 
     } 
     else if (this.inCatalinaServiceElement && "Connector".equals(localName) && "HTTP/1.1".equals(atts.getValue("protocol"))) { 

      if ((atts.getValue("SSLEnabled") == null || "false".equals(atts.getValue("SSLEnabled"))) && 
        (atts.getValue("secure") == null || "false".equals(atts.getValue("secure"))) && 
        (atts.getValue("scheme") == null || "http".equals(atts.getValue("scheme")))) { 

         final String portStr = atts.getValue("port"); 
         if (portStr != null) { 

          this.map.put("httpPort", portStr); 
         } 
         final String redirectPortStr = atts.getValue("redirectPort"); 
         if (redirectPortStr != null) { 

          this.map.put("httpRedirectPort", redirectPortStr); 
         } 
        } 
     } 
    } 

    @Override 
    public void endElement(final String uri, final String localName, final String qName) throws SAXException { 

     if (this.inCatalinaServiceElement && "Service".equals(localName)) { 

      this.inCatalinaServiceElement = false; 
     } 
     else if (this.inServerElement && "Server".equals(localName)) { 

      this.inServerElement = false; 
     } 
    } 

    @Override 
    public void endDocument() throws SAXException { 

     this.inServerElement = false; 
     this.inCatalinaServiceElement = false; 
    } 

    @Override 
    public void characters(final char[] ch, final int start, final int length) throws SAXException { } 

    @Override 
    public void endPrefixMapping(final String prefix) throws SAXException { } 

    @Override 
    public void ignorableWhitespace(final char[] ch, final int start, final int length) throws SAXException { } 

    @Override 
    public void processingInstruction(final String target, final String data) throws SAXException { } 

    @Override 
    public void setDocumentLocator(final Locator locator) { } 

    @Override 
    public void skippedEntity(final String name) throws SAXException { } 

    @Override 
    public void startPrefixMapping(final String prefix, final String uri) throws SAXException { } 
} 

}

+0

Enfoque interesante, aunque demasiado sucio para el código de producción. +1 por originalidad. –

+0

Funciona, sin embargo, ata el uso con Tomcat 7. Adicional, no para esta respuesta, sino para la publicación original, el rendimiento de .getLocalhost() es muy pobre en algún sistema, probablemente debido a la búsqueda de IP6 desde Java 1.4.1. Me pregunto si podríamos hacer una solicitud de volcado para servlet después del inicio para obtener información necesaria a través de HttpRequest. – lent