Как мне прочитать файл манифеста для веб-приложения, работающего в Apache Tomcat? - PullRequest
46 голосов
/ 05 марта 2009

У меня есть веб-приложение, которое содержит файл манифеста, в котором я записываю текущую версию своего приложения во время задачи сборки ant. Файл манифеста создан правильно, но когда я пытаюсь прочитать его во время выполнения, я получаю некоторые странные побочные эффекты. Мой код для чтения в манифесте выглядит примерно так:

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

Когда я присоединяю eclipse к tomcat, я вижу, что приведенный выше код работает, но, похоже, он получает файл манифеста, отличный от того, который я ожидал, что я могу сказать, потому что версия ant и метка времени сборки отличаются. Затем я положил туда «META-INFFFF», и приведенный выше код все еще работает! Это означает, что я читаю какой-то другой манифест, а не мой. Я тоже пробовал

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

Но результат был тот же. Как правильно читать файл манифеста из веб-приложения, запущенного в tomcat?

Редактировать : Спасибо за предложения. Кроме того, я должен отметить, что я я работаю tomcat автономно; Я запускаю его из командной строки, а затем присоединяю к работающему экземпляру в отладчике Eclipse. Это не должно иметь значение, не так ли?

Ответы [ 7 ]

89 голосов
/ 05 марта 2009

Возможно, ваши побочные эффекты связаны с тем, что почти все банки содержат MANIFEST.MF, а вы не получаете правильный. Чтобы прочитать MANIFEST.MF из веб-приложения, я бы сказал:

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

Обратите внимание, что запуск Tomcat из Eclipse отличается от запуска Tomcat, когда Eclipse играет с загрузчиком классов.

11 голосов
/ 18 марта 2010

немного поздно, но это работает для меня (веб-приложение в 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}"));
3 голосов
/ 02 декабря 2012

Попробуйте использовать jcabi-манифесты , который выполняет всю эту загрузку за вас. Например:

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

загружает My-Version атрибут из одного из доступных MANIFEST.MF файлов.

Важно отметить, что (более подробная информация здесь ) в большинстве веб-контейнеров текущий загрузчик классов потоков не совпадает с загрузчиком классов контекста сервлета. Вот почему вы должны добавить свой контекст сервлета в регистр во время выполнения ( больше информации ):

Manifests.append(servletContext);

Кроме того, проверьте это: http://www.yegor256.com/2014/07/03/how-to-read-manifest-mf.html

2 голосов
/ 22 июня 2015

Правильный манифест существует в корне приложения на сервере. Найдите корень приложения, например, узнав classpath вашего класса:

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

Затем замените путь выше на найденный путь: Пример Glassfish:

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

Это работает для меня.

2 голосов
/ 05 марта 2009

По умолчанию загрузчики классов работают с родительским элементом, прежде чем пытаться найти свои собственные ресурсы. Так что если у загрузчика родительского класса есть какой-либо доступный манифест, это то, что вы получите. На самом деле серверы приложений не обязательно делают это, чтобы приложения могли переопределять версии библиотек. Кроме того, загрузчики классов могут иметь несколько jar и, следовательно, несколько манифестов.

Возможно, он сможет получить URL ресурса одного из ресурсов с уникальным именем. Откройте соединение. Приведение к JarURLConnection. Получи JarFile. Загрузите манифест из этого. Это может не сработать, особенно если Tomcat взрывает войну.

[Update] Конечно, сам файл войны не находится на пути к классам. У пути к классам будет что-то вроде WEB-INF / lib / ( .jar | .zip) и WEB-INF / classes /. Получение ресурса из ServletContext должно работать.

Лучшее решение: сделать что-то другое. :)

1 голос
/ 05 марта 2009

Не знаю об «официальном» способе его чтения, но если файл MANIFEST.MF не может быть правильно загружен как ресурс, как насчет попытки извлечь его путь из «ServletContext.getRealPath ()» в какой веб-путь определен в вашем приложении?

Запись версии приложения в другое место (файл свойств в WEB-INF / classes) с помощью ant во время сборки - это еще одно решение, которое мне приходит в голову.

0 голосов
/ 30 августа 2015

Это то, что я делаю для печати различных версий в лог-файл. Я жестко запрограммировал расширенный путь, но приложения могут использовать servletContext.getRealPath("/") для чтения полного пути к папке веб-приложения. Может печатать только что заданные библиотеки или все из папки 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();
}
...