2009-03-05 4 views
45

Ho una webapp che contiene un file manifest, in cui scrivo la versione corrente della mia applicazione durante un'attività di compilazione ant. Il file manifest è stato creato correttamente, ma quando provo a leggerlo durante il runtime, ottengo alcuni strani effetti collaterali. Il mio codice per la lettura nel manifesto è qualcosa di simile:Come faccio a leggere il file manifest per una webapp in esecuzione in apache tomcat?

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

Quando attribuisco Eclipse per Tomcat, vedo che il codice precedente funziona, ma sembra per ottenere un file manifesto diverso da quello che mi aspettavo, che Posso dirlo perché la versione della formica e il timestamp della build sono entrambi diversi. Quindi, inserisco "META-INFFFF" e il codice sopra funziona ancora! Ciò significa che sto leggendo qualche altro manifesto, non il mio. Ho anche provato

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

Ma il risultato è stato lo stesso. Qual è il modo corretto di leggere il file manifest dall'interno di una webapp in esecuzione in tomcat?

Modifica: Grazie per i suggerimenti finora. Inoltre, devo notare che I am running tomcat standalone; Lo avvio dalla riga di comando e quindi si collega all'istanza in esecuzione nel debugger di Eclipse. Questo non dovrebbe fare la differenza, dovrebbe?

+0

La risposta di @ PascalThivent è la soluzione giusta. Aggiungi una gestione delle eccezioni nel caso in cui MANIFEST non esista (ie.IDE) e dovrebbe essere A1. – jmelanson

+0

Questo metodo universale mi ha aiutato: [http://stackoverflow.com/a/29103019/3158918] – user3158918

risposta

1

Non conosco un modo "ufficiale" di leggerlo, ma se MANIFEST.MF non può essere caricato correttamente come risorsa, come fare per ricavarne il percorso da "ServletContext.getRealPath()" su qualche percorso web definito nella tua app?

Scrivere la versione dell'app anche in un altro posto (un file di proprietà in WEB-INF/classi) da formica durante la compilazione è un'altra soluzione che mi viene in mente.

86

Forse i tuoi effetti collaterali derivano dal fatto che quasi tutti i barattoli includono un MANIFEST.MF e non stai ottenendo quello giusto. Per leggere il MANIFEST.MF dalla webapp, direi:

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

Si prega di notare che l'esecuzione di Tomcat da Eclipse non è la stessa cosa che lanciare Tomcat solo come Eclipse gioca con il classloader.

+1

In effetti, il manifest di guerra non si troverà sul classpath. –

+2

+1 per dare il codice effettivo che funziona effettivamente. –

+4

Questa è chiaramente la risposta giusta +1 –

2

Il modo predefinito utilizzato dai programmi di caricamento classe è di posticipare il padre prima di tentare di cercare le proprie risorse. Quindi se un caricatore di classe genitore ha qualche manifest disponibile, questo è ciò che otterrai. Di fatto, i server delle app non lo fanno necessariamente, per consentire alle applicazioni di sovrascrivere le versioni delle librerie. Inoltre, i caricatori di classi possono avere più vasi e quindi più manifesti.

Potrebbe essere possibile ottenere un URL di risorsa di una delle risorse con un nome univoco. Apri una connessione. Trasmissione allo JarURLConnection. Prendi il JarFile. Carica il manifest da quello. Potrebbe non funzionare, specialmente se Tomcat esplode la guerra.

[Aggiorna] Naturalmente, il file di guerra non è sul classpath. Il classpath avrà qualcosa come WEB-INF/lib/(.jar | .zip) e WEB-INF/classes /. Ottenere una risorsa da ServletContext dovrebbe funzionare.

Soluzione migliore: fare qualcosa di diverso.:)

10

un po 'tardi, ma questo funziona per me (appl web 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

fai attenzione: seguendo [RFC-822] (http://www.ietf.org/rfc/rfc0822.txt) troverai dei problemi usando 'Proprietà' dato che i valori lunghi sono interrotti su più righe. User 'Manifest' class invece. –

3

tenta di utilizzare jcabi-manifests, che fa tutto questo lavoro di carico per voi. Per esempio:

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

carichi My-Version attributo da uno dei MANIFEST.MF file disponibili.

Importante ricordare che (più dettagli sono here) nella maggior parte dei contenitori Web il programma di caricamento classe thread corrente non è lo stesso del caricatore classe contesto servlet. Ecco perché si dovrebbe aggiungere vostro contesto servlet per il registro in fase di esecuzione (more info):

Manifests.append(servletContext); 

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

2

Il manifesto proprio in radice dell'applicazione sul server. Scopri la radice appication, per esempio scoprendo classpath della classe:

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

quindi sostituire il percorso di cui sopra con il percorso della fondazione: Esempio Glassfish:

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

il lavoro per me.

0

Questo è ciò che faccio per stampare varie versioni in un file di registro. Ho hardcoded un percorso espanso ma le app possono utilizzare servletContext.getRealPath("/") per leggere un percorso completo alla cartella webapp. Può stampare solo le librerie fornite o qualsiasi cosa dalla cartella 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(); 
}