¿Cómo leo el archivo de manifiesto para una aplicación web que se ejecuta en apache tomcat?

Tengo una aplicación web que contiene un archivo de manifiesto, en el que escribo la versión actual de mi aplicación durante una tarea de comstackción de ant. El archivo de manifiesto se crea correctamente, pero cuando trato de leerlo durante el tiempo de ejecución, obtengo algunos efectos secundarios extraños. Mi código para leer en el manifiesto es algo como esto:

InputStream manifestStream = Thread.currentThread() .getContextClassLoader() .getResourceAsStream("META-INFFFF/MANIFEST.MF"); try { Manifest manifest = new Manifest(manifestStream); Attributes attributes = manifest.getMainAttributes(); String impVersion = attributes.getValue("Implementation-Version"); mVersionString = impVersion; } catch(IOException ex) { logger.warn("Error while reading version: " + ex.getMessage()); } 

Cuando adjunto eclipse a tomcat, veo que el código anterior funciona, pero parece obtener un archivo de manifiesto diferente del que esperaba, lo cual puedo decir porque la versión ant y la marca de tiempo de comstackción son ambas diferentes. Luego, puse “META-INFFFF” allí, ¡y el código anterior aún funciona! Esto significa que estoy leyendo algún otro manifiesto, no el mío. También intenté

 this.getClass().getClassLoader().getResourceAsStream(...) 

Pero el resultado fue el mismo. ¿Cuál es la forma correcta de leer el archivo de manifiesto desde dentro de una aplicación web que se ejecuta en tomcat?

Editar : Gracias por las sugerencias hasta ahora. Además, debería tener en cuenta que estoy ejecutando tomcat independiente; Lo lanzo desde la línea de comando y luego lo conecto a la instancia en ejecución en el depurador de Eclipse. Eso no debería hacer la diferencia, ¿o sí?

Tal vez sus efectos secundarios provengan del hecho de que casi todos los flasks incluyen un MANIFEST.MF y no está obteniendo el correcto. Para leer el MANIFEST.MF de la aplicación web, diría:

 ServletContext application = getServletConfig().getServletContext(); InputStream inputStream = application.getResourceAsStream("/META-INF/MANIFEST.MF"); Manifest manifest = new Manifest(inputStream); 

Tenga en cuenta que ejecutar Tomcat desde Eclipse no es lo mismo que ejecutar Tomcat solo cuando Eclipse juega con el cargador de clases.

un poco tarde, pero esto funciona para mí (aplicación web en Glassfish)

 Properties prop = new Properties(); prop.load(getServletContext().getResourceAsStream("/META-INF/MANIFEST.MF")); System.out.println("All attributes:" + prop.stringPropertyNames()); System.out.println(prop.getProperty("{whatever attribute you want}")); 

Intenta usar jcabi-manifiestos , que hace todo este trabajo de carga por ti. Por ejemplo:

 String version = Manifests.read("My-Version"); 

carga el atributo My-Version de uno de los archivos MANIFEST.MF disponibles.

Es importante mencionar que (hay más detalles aquí ) en la mayoría de los contenedores web actuales, el cargador de clases de subprocesos no es lo mismo que el cargador de clases de contexto de servlet. Es por eso que debe agregar su contexto de servlet al registro en tiempo de ejecución ( más información ):

 Manifests.append(servletContext); 

Además, mira esto: http://www.yegor256.com/2014/07/03/how-to-read-manifest-mf.html

La forma predeterminada en que los cargadores de clases funcionan es diferir al padre antes de intentar buscar sus propios recursos. Entonces, si un cargador de clases padre tiene algún manifiesto disponible, eso es lo que obtendrás. De hecho, los servidores de aplicaciones no necesariamente hacen esto para permitir que las aplicaciones anulen las versiones de las bibliotecas. Además, los cargadores de clase pueden tener múltiples jarras y, por lo tanto, manifiestos múltiples.

Es posible que pueda obtener un URL de recurso de uno de sus recursos con nombre único. Abra una conexión. JarURLConnection a JarURLConnection . Obtenga el JarFile . Cargue el manifiesto de eso. Eso puede no funcionar, particularmente si Tomcat explota la guerra.

[Actualización] Por supuesto, el archivo de guerra en sí no está en el classpath. El classpath tendrá algo como WEB-INF / lib / ( .jar | .zip) y WEB-INF / classes /. Obtener un recurso del ServletContext debería funcionar.

La mejor solución: haz algo diferente. 🙂

El manifiesto correcto existe en la raíz de la aplicación en el servidor. Descubra la raíz de la aplicación, por ejemplo, descubriendo el classpath de su clase:

 String rootPath = getClass().getProtectionDomain().getCodeSource().getLocation().getPath() 

A continuación, reemplace la ruta anterior con la ruta de acceso fundamentada: ejemplo de Glassfish:

 /applications//META-INF/MANIFEST.MF 

Funciona para mí

No se conoce una forma “oficial” de leerlo, pero si MANIFEST.MF no se puede cargar correctamente como un recurso, ¿qué hay de intentar derivar su ruta de un “ServletContext.getRealPath ()” en alguna ruta web? definido en tu aplicación?

Escribir la versión de la aplicación también a algún otro lugar (un archivo de propiedades en WEB-INF / classes) por ant durante la comstackción es otra solución que se me viene a la mente.

Esto es lo que hago para imprimir varias versiones en un archivo de registro. He codificado una ruta expandida, pero las aplicaciones pueden usar servletContext.getRealPath("/") para leer una ruta completa a la carpeta de aplicaciones web. Puede imprimir solo bibliotecas dadas o todo desde la carpeta lib.

 // print library versions (jersey-common.jar, jackson-core-2.6.1.jar) try { List jars = Arrays.asList( "jersey-common", "jackson-core", "openjpa", "mylib" ); StringBuilder verbuf = new StringBuilder(); for(File file : new File("/opt/tomcat/webapps/myapp/WEB-INF/lib/").listFiles() ) { String name = file.getName(); if (file.isDirectory() || !file.isFile() || !name.endsWith(".jar") ) continue; name = name.substring(0, name.length()-4); boolean found = jars.contains(name); if (!found) { int idx = name.lastIndexOf('-'); if (idx>0) found = jars.contains( name.substring(0, idx) ); } if (!found) continue; JarFile jarFile = new JarFile(file, false); try { String ver; Manifest mf = jarFile.getManifest(); if (mf!=null) { ver = mf.getMainAttributes().getValue("Bundle-Version"); if (ver==null || ver.isEmpty()) ver = mf.getMainAttributes().getValue("Implementation-Version"); } else ver=null; if (verbuf.length()>0) verbuf.append(", "); verbuf.append(name + "=" + (ver!=null?ver:"") ); } finally { jarFile.close(); } } System.out.println( verbuf.toString() ); } catch(Exception ex) { ex.printStackTrace(); }