Jar Archiv nach Manifest Dateien durchsuchen

cHrIzMaStEr

Grünschnabel
Hallo und Guten Tag,

ich habe folgendes Problem:

Ich habe irgendwo auf dem Dateisystem ein .jar Archiv liegen (z.B. test.jar). Diese Archiv enthält weitere .jar Archive (oder auch .war - z.B. 1.jar / 2.jar / 3.war / ...) und natürlich den META-INF/MANIFEST.MF Ordner mit der Manifest Datei.
Die Ausgabe dieser ersten Manifest Datei (aus test.jar) ist auch kein Problem, allerdings möchte ich auf alle Manifest Dateien der Jar Archive innerhalb des test.jar Archivs zugreifen, also auch auf die Manifest Dateien aus den .jar Archiven (1.jar / 2.jar / 3.war / ...) die im ersten Archiv (test.jar) enthalten sind!

Leider bekomme ich das nur hin, wenn ich erst jedes Archiv entpacke und dann auf dem Dateisystem nach der MANIFEST.MF suche.... Gibt es eine Möglichkeit ohne jedes Archiv zu entpacken auf die Dateien zuzugriefen!! Dazu müsste ich ja quasi beim rekursiven Aufruf der Methode welche die JAR Einträge auflistet, die jeweilig akutelle Datei angeben (also 1.jar / 2.jar / 3.war / ...) Oder!?

Vlt könnt ihr mir ja helfen oder mir sagen das es nur funktioniert wenn man das Archiv entpackt

Gruß und Danke schonmal...
chrizmaster
 
Hallo!

Eine Möglichkeit sähe so aus:
Java:
/**
 * 
 */
package de.tutorials;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;

/**
 * @author Thomas.Darimont
 */
public class JarFileAnalyzer {

  /**
   * @param args
   */
  public static void main(String[] args) throws Exception {
    JarFile jarFile = new JarFile("c:/tmp/commons.jar");
    List<Manifest> manifests = lookForManifestFiles(jarFile, true);
    for (Manifest manifest : manifests) {
      System.out.println(manifest.getMainAttributes().getValue("Implementation-Title"));
    }

  }


  private static List<Manifest> lookForManifestFiles(JarFile jarFile, boolean pseudoRecursive) throws Exception {
    List<Manifest> manifests = new ArrayList<Manifest>();
    manifests.add(jarFile.getManifest());
    if (pseudoRecursive) {
      Enumeration<JarEntry> jarEntries = jarFile.entries();
      while (jarEntries.hasMoreElements()) {
        JarEntry jarEntry = jarEntries.nextElement();
        if (jarEntry.getName().toLowerCase().matches(".*\\.jar$")) {
          JarInputStream jarInputStream = new JarInputStream(jarFile.getInputStream(jarEntry));
          manifests.add(jarInputStream.getManifest());
          jarInputStream.close();
        }
      }
    }

    return manifests;
  }
}
...das wäre mal die dummy-Implementierung für den Fall, dass die Verschachtelung nicht größer als 1 (-> jar in jar) ist.

Gruß Tom
 
Danke schonmal für die schnelle Antwort... werde mir das gleich mal anschauen und versuchen umzusetzen...!

Leider kann es aber sein, das die Verschachtelung noch tiefer geht....

z.B.

xxx.jar
xxx.war​
xxx.jar​
xxx.jar​
xxx.jar​
xxx.jar​
xxx.jar​
xxx.jar​


gruß
chrizmaster
 
Oder gibt es eine Möglichkeit von JarEntry zu JarFile zu konvertieren!!

Dann könnte man der Methode welche das JarFile übergeben kriegt und die Entry's ausließt, dass akutelle Entry als JarFile beim rekursiven Aufruf übergeben....!?

mhhh oder gibt es noch eine andere Möglichkeit...!!

gruß und danke
chrizmaster
 
Hallo!

schau mal hier:
Java:
/**
 * 
 */
package de.tutorials;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;

/**
 * @author Thomas.Darimont
 */
public class JarFileAnalyzer {

  /**
   * @param args
   */
  public static void main(String[] args) throws Exception {
    JarFile jarFile = new JarFile("c:/tmp/base.jar");
    List<Manifest> manifests = lookForManifestFiles(jarFile, true);
    for (Manifest manifest : manifests) {
      System.out.println(manifest.getMainAttributes().getValue("Implementation-Title"));
    }

  }


  private static List<Manifest> lookForManifestFiles(JarFile jarFile, boolean recursive) throws Exception {
    List<Manifest> manifests = new ArrayList<Manifest>();
    manifests.add(jarFile.getManifest());
    if (recursive) {
      Enumeration<JarEntry> jarEntries = jarFile.entries();
      while (jarEntries.hasMoreElements()) {
        JarEntry jarEntry = jarEntries.nextElement();
        if (jarEntry.getName().toLowerCase().matches(".*\\.(jar|war)$")) {
          System.out.println("nested jarEntry: " + jarEntry.getName());
          JarInputStream jarInputStream = new JarInputStream(jarFile.getInputStream(jarEntry));
          manifests.add(jarInputStream.getManifest());
          lookForManifestFilesInNestedJarEntry(jarInputStream, manifests);
          jarInputStream.close();
        }
      }
    }

    return manifests;
  }


  private static void lookForManifestFilesInNestedJarEntry(JarInputStream jarInputStream,
    List<Manifest> manifests) throws Exception {
    JarEntry nestedJarEntry = null;
    while ((nestedJarEntry = jarInputStream.getNextJarEntry()) != null) {
      if (nestedJarEntry.getName().toLowerCase().matches(".*\\.(jar|war)$")) {
        System.out.println("nested jarEntry: " + nestedJarEntry.getName());
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        int len = 0;
        byte[] buffer = new byte[32768];
        while ((len = jarInputStream.read(buffer)) > 0) {
          byteArrayOutputStream.write(buffer, 0, len);
        }
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        JarInputStream nestedJarInputStream = new JarInputStream(byteArrayInputStream);
        manifests.add(nestedJarInputStream.getManifest());
        lookForManifestFilesInNestedJarEntry(nestedJarInputStream, manifests);
        nestedJarInputStream.close();
      }
      jarInputStream.closeEntry();
    }
  }

}

Ausgabe:
Code:
nested jarEntry: inner.jar
nested jarEntry: innerinner.jar
nested jarEntry: innerinnerinner.war
base
inner
innerinner
innerinnerinner

Gruß Tom
 

Anhänge

Hallo, ich nochmal....

also habs soweit eingebunden und bissl verändert und läuft alles bestens! Nochmal zum Verständnis, wozu die folgenden Zeilen da sind:

Code:
...
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int len = 0;
byte[] buffer = new byte[32768];
while ((len = jarInputStream.read(buffer)) > 0) {
byteArrayOutputStream.write(buffer, 0, len);
}
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
JarInputStream nestedJarInputStream = new JarInputStream(byteArrayInputStream
...

Wozu dient der ByteArrayInput/OutputStream

gruß
chrizmaster
 
Hallo!

Damit entpacke ich die genesteten Jars temporär in den Speicher... du wolltest sie ja nicht auf der Platte haben, jedoch müssen sie zum Untersuchen eben entpackt werden. Also vorsicht damit ;-)

Gruß Tom
 
Zurück