2009-03-05 11 views
45

Ich habe eine Webapp, die eine Manifest-Datei enthält, in der ich die aktuelle Version meiner Anwendung während einer Ameisen-Build-Aufgabe schreibe. Die Manifestdatei wird korrekt erstellt, aber wenn ich versuche, sie während der Laufzeit einzulesen, bekomme ich einige seltsame Nebenwirkungen. Mein Code für im Manifest zu lesen ist so etwas wie dieses:Wie lese ich die Manifestdatei für eine Webapp, die in Apache Tomcat ausgeführt wird?

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

Als ich tomcat eclipse anhängen, ich sehe, dass der obige Code funktioniert, aber es scheint eine andere Manifest-Datei als das bekommen ich erwartet hatte, die Ich kann sagen, weil die Ameisenversion und der Build-Zeitstempel beide unterschiedlich sind. Dann lege ich "META-INFFFF" drin, und der obige Code funktioniert immer noch! Das bedeutet, dass ich ein anderes Manifest lese, nicht meins. Ich versuchte auch

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

Aber das Ergebnis war das gleiche. Was ist der richtige Weg, um die Manifest-Datei aus einer Webapp in Tomcat zu lesen?

Bearbeiten: Danke für die Vorschläge so weit. Auch sollte ich beachten, dass ich bin läuft Tomcat Standalone; Ich starte es von der Befehlszeile aus und verknüpfe es dann mit der laufenden Instanz im Debugger von Eclipse. Das sollte keinen Unterschied machen, oder?

+0

@ PascalThivents Antwort ist der richtige Weg dazu. Fügen Sie eine Ausnahmebehandlung für den Fall hinzu, dass Ihr MANIFEST nicht existiert (zB.IDE) und es sollte A1 sein. – jmelanson

+0

Diese universelle Methode hat mir geholfen: [http://stackoverflow.com/a/29103019/3158918] – user3158918

Antwort

1

Ich weiß nichts von einem "offiziellen" Weg, es zu lesen, aber wenn die MANIFEST.MF nicht richtig als Ressource geladen werden kann, wie wäre es mit dem Versuch, seinen Pfad von einem "ServletContext.getRealPath()" abzuleiten auf einem bestimmten Webpfad in Ihrer App definiert?

Das Schreiben der App-Version auch an einen anderen Ort (eine Eigenschaft Datei in WEB-INF/Klassen) von Ameisen während des Baus ist eine andere Lösung, die mir in den Sinn kommt.

86

Vielleicht sind Ihre Nebenwirkungen darauf zurückzuführen, dass fast alle Gläser eine MANIFEST.MF enthalten und Sie nicht die richtige bekommen. Um die MANIFEST.MF aus der Webapp zu lesen, würde ich sagen:

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

Bitte beachten Sie, dass läuft Tomcat aus Eclipse ist nicht das gleiche wie läuft allein Tomcat als Eclipse-mit dem Classloader spielt.

+1

In der Tat wird das Manifest des Krieges nicht auf dem Klassenpfad sein. –

+2

+1 für tatsächlichen Code, der tatsächlich funktioniert. –

+4

Dies ist eindeutig die richtige Antwort +1 –

2

Die Standardmethode, die Klassenladeprogramme verwenden, besteht darin, auf das übergeordnete Element zu verweisen, bevor versucht wird, ihre eigenen Ressourcen zu suchen. Wenn also ein Elternklasse-Loader ein Manifest zur Verfügung hat, erhalten Sie das. Tatsächlich müssen App-Server dies nicht unbedingt tun, damit Anwendungen Versionen von Bibliotheken überschreiben können. Darüber hinaus können Klassenlader mehrere Gläser und damit mehrere Manifeste enthalten.

Möglicherweise ist es möglich, eine Ressourcen-URL einer Ihrer eindeutig benannten Ressourcen zu erhalten. Öffnen Sie eine Verbindung. Gegossen zu JarURLConnection. Holen Sie sich die JarFile. Laden Sie das Manifest daraus. Das kann nicht funktionieren, besonders wenn Tomcat den Krieg explodiert.

[Update] Natürlich ist die War-Datei selbst nicht auf dem Klassenpfad. Der Klassenpfad wird so etwas wie WEB-INF/lib/(.jar | .zip) und WEB-INF/classes/haben. Eine Ressource von ServletContext zu bekommen sollte funktionieren.

Beste Lösung: Tun Sie etwas anderes.:)

10

ein bisschen spät, aber das funktioniert für mich (Web Appl in 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}")); 
+9

beachten Sie: nach [RFC-822] (http://www.ietf.org/rfc/rfc0822.txt) finden Sie Probleme mit 'Properties', da die langen Werte in mehr Zeilen aufgeteilt sind. Benutzer 'Manifest' Klasse stattdessen. –

3

Try jcabi-manifests zu verwenden, die diesen Laden alle Arbeit für Sie erledigt. Zum Beispiel:

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

Lasten My-Version Attribut von einem der verfügbaren MANIFEST.MF Dateien.

Wichtig zu erwähnen, dass (mehr Details sind here) in den meisten Web-Containern aktuellen Thread-Klasse-Lader ist nicht das gleiche wie Servlet Kontext-Klasse-Lader. Deshalb sollten Sie Ihre Servletkontext in das Register in Runtime (more info) anhängen soll:

Manifests.append(servletContext); 

Auch check this out: http://www.yegor256.com/2014/07/03/how-to-read-manifest-mf.html

2

Die richtige Manifest besteht in der Anwendung root auf dem Server. die appication Wurzel Finden Sie heraus, zum Beispiel durch Classpath Ihre Klasse herauszufinden:

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

dann den Pfad ersetzen oben mit dem gegründeten Pfad: Glassfish Beispiel:

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

Es ist für mich arbeiten.

0

Dies ist, was ich tue, um verschiedene Versionen in eine Logdatei zu drucken. Ich habe einen erweiterten Pfad fest programmiert, aber Apps können servletContext.getRealPath("/") verwenden, um einen vollständigen Pfad zum Webapp-Ordner zu lesen. Darf nur bestimmte Bibliotheken oder alles aus dem lib-Ordner drucken.

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