web-dev-qa-db-fra.com

Comment lire le fichier manifeste d'une webapp s'exécutant dans Apache tomcat?

J'ai une webapp qui contient un fichier manifeste, dans lequel j'écris la version actuelle de mon application lors d'une tâche de génération de fourmis. Le fichier manifeste est créé correctement, mais lorsque j'essaie de le lire pendant l'exécution, j'obtiens des effets secondaires étranges. Mon code pour lire dans le manifeste est quelque chose comme ceci:

    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());
    }

Lorsque j'attache Eclipse à Tomcat, je vois que le code ci-dessus fonctionne, mais il semble obtenir un fichier manifeste différent de celui que j'attendais, ce que je peux dire parce que la version ant et l'horodatage de la construction sont tous deux différents. Ensuite, j'ai mis "META-INFFFF" là-dedans, et le code ci-dessus fonctionne toujours! Cela signifie que je lis un autre manifeste, pas le mien. J'ai aussi essayé

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

Mais le résultat était le même. Quelle est la bonne façon de lire le fichier manifeste depuis l'intérieur d'une webapp s'exécutant dans tomcat?

Modifier: Merci pour les suggestions jusqu'à présent. En outre, je dois noter que je suis exécutant Tomcat autonome; Je le lance depuis la ligne de commande, puis je l'attache à l'instance en cours d'exécution dans le débogueur d'Eclipse. Cela ne devrait pas faire de différence, n'est-ce pas?

46
Nik Reiman

Peut-être que vos effets secondaires proviennent du fait que presque tous les pots incluent un MANIFEST.MF et que vous n'obtenez pas le bon. Pour lire le MANIFEST.MF de la webapp, je dirais:

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

Veuillez noter que l'exécution de Tomcat à partir d'Eclipse n'est pas la même chose que l'exécution de Tomcat seul car Eclipse joue avec le chargeur de classe.

89
Pascal Thivent

un peu tard, mais cela fonctionne pour moi (application web dans 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}"));
11
javadude

Essayez d'utiliser jcabi-manifests , qui fait tout ce travail de chargement pour vous. Par exemple:

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

charge l'attribut My-Version à partir de l'un des fichiers MANIFEST.MF disponibles.

Il est important de mentionner que (plus de détails sont ici ) dans la plupart des conteneurs Web, le chargeur de classe de thread actuel n'est pas le même que le chargeur de classe de contexte de servlet. C'est pourquoi vous devez ajouter votre contexte de servlet au registre lors de l'exécution ( plus d'informations ):

Manifests.append(servletContext);

Consultez également ceci: http://www.yegor256.com/2014/07/03/how-to-read-manifest-mf.html

3
yegor256

Par défaut, les chargeurs de classe fonctionnent pour s'en remettre au parent avant d'essayer de rechercher leurs propres ressources. Donc, si un chargeur de classe parent a un manifeste disponible, c'est ce que vous obtiendrez. En fait, les serveurs d'applications ne le font pas nécessairement, pour permettre aux applications de remplacer les versions des bibliothèques. De plus, les chargeurs de classe peuvent avoir plusieurs pots et donc plusieurs manifestes.

Il peut être en mesure d'obtenir une URL de ressource de l'une de vos ressources au nom unique. Ouvrez une connexion. Cast sur JarURLConnection. Obtenez le JarFile. Chargez le manifeste à partir de cela. Cela peut ne pas fonctionner, en particulier si Tomcat explose la guerre.

[Mise à jour] Bien sûr, le fichier war lui-même n'est pas sur le chemin de classe. Le chemin de classe aura quelque chose comme WEB-INF/lib/(. Jar. Zip) et WEB-INF/classes /. Obtenir une ressource à partir de ServletContext devrait fonctionner.

Meilleure solution: faites quelque chose de différent. :)

2

Le manifeste approprié existe dans la racine de l'application sur le serveur. Découvrez la racine de l'application, par exemple en recherchant le chemin de classe de votre classe:

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

Remplacez ensuite le chemin ci-dessus par le chemin fondé: Exemple de Glassfish:

/applications/<webProject>/META-INF/MANIFEST.MF

Ça marche pour moi.

2
user3687374

Je ne connais pas une façon "officielle" de le lire, mais si le MANIFEST.MF ne peut pas être correctement chargé en tant que ressource, que diriez-vous d'essayer de dériver son chemin à partir d'un "ServletContext.getRealPath ()" sur un chemin Web défini dans votre application?

L'écriture de la version de l'application également à un autre endroit (un fichier de propriétés dans WEB-INF/classes) par ant pendant la construction est une autre solution qui me vient à l'esprit.

1
david a.

Voici ce que je fais pour imprimer différentes versions dans un fichier journal. J'ai codé en dur un chemin développé, mais les applications peuvent utiliser servletContext.getRealPath("/") pour lire un chemin complet vers le dossier webapp. Peut imprimer les bibliothèques données ou tout ce qui vient du dossier lib.

// print library versions (jersey-common.jar, jackson-core-2.6.1.jar)
try {
    List<String> 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();
}
0
Whome