Как прочитать файл манифеста для webapp, запущенного в apache tomcat?

У меня есть webapp, который содержит файл манифеста, в котором я пишу текущую версию моего приложения во время задачи сборки 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(...)

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

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

Ответ 1

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

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

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

Ответ 2

немного поздно, но это работает для меня (веб-приложение в 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

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

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

Ответ 4

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

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

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

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

Ответ 5

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

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

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

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

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

Ответ 6

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

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

Ответ 7

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