web-dev-qa-db-ja.com

Apache Tomcatで実行されているwebappのマニフェストファイルを読み取るにはどうすればよいですか?

マニフェストファイルを含む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(...)

しかし、結果は同じでした。 Tomcatで実行されているWebアプリの内部からマニフェストファイルを読み取る適切な方法は何ですか?

編集:これまでの提案に感謝します。また、私はTomcatをスタンドアロンで実行していることに注意してくださいam。コマンドラインから起動し、Eclipseのデバッガーで実行中のインスタンスにアタッチします。違いはないはずですよね?

46
Nik Reiman

おそらく、あなたの副作用は、ほぼすべてのjarにMANIFEST.MFが含まれており、適切なjarを取得していないという事実に起因する可能性があります。 webappからMANIFEST.MFを読み取るには、次のように言います。

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

Eclipseがクラスローダーで動作するため、EclipseからTomcatを実行することは、Tomcatを単独で実行することとは異なります。

89
Pascal Thivent

少し遅れましたが、これは私にとってはうまくいきます(Glassfishのweb appl)

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}"));
11
javadude

jcabi-manifests を使用してみてください。これにより、このロードがすべて自動的に行われます。例えば:

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

ロードMy-Version使用可能なMANIFEST.MFファイル。

(詳細は here です)ほとんどのWebコンテナでは、現在のスレッドクラスローダーはサーブレットコンテキストクラスローダーとは異なります。そのため、実行時にサーブレットコンテキストをレジスタに追加する必要があります( 詳細 ):

Manifests.append(servletContext);

また、これをチェックしてください: http://www.yegor256.com/2014/07/03/how-to-read-manifest-mf.html

3
yegor256

クラスローダーが動作するデフォルトの方法は、独自のリソースを検索する前に親に遅延させることです。そのため、親クラスローダーでマニフェストを使用できる場合は、それが取得されます。実際、アプリケーションがライブラリのバージョンをオーバーライドできるようにするために、アプリケーションサーバーは必ずしもこれを行う必要はありません。さらに、クラスローダーには複数のjarがあり、したがって複数のマニフェストを持つことができます。

一意の名前のリソースのいずれかのリソースURLを取得できる場合があります。接続を開きます。 JarURLConnectionにキャストします。 JarFileを取得します。それからマニフェストをロードします。特にTomcatが戦争を爆発させた場合、それはうまくいかないかもしれません。

[更新]もちろん、warファイル自体はクラスパスにはありません。クラスパスには、WEB-INF/lib /(。jar。Zip​​)やWEB-INF/classes /のようなものがあります。 ServletContextからリソースを取得できます。

最善の解決策:何か違うことをしてください。 :)

正しいマニフェストは、サーバーのアプリケーションルートに存在します。たとえば、クラスのクラスパスを見つけることにより、アプリケーションルートを見つけます。

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

次に、上記のパスを作成されたパスに置き換えます:Glassfishの例:

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

それは私のために働く。

2
user3687374

「公式」な読み方については知りませんが、MANIFEST.MFをリソースとして適切にロードできない場合は、Webパス上の「ServletContext.getRealPath()」からパスを派生させてみてください。アプリで定義されていますか?

ビルド中にantによってアプリバージョンを他の場所(WEB-INF/classesのプロパティファイル)に書き込むことも、私の頭に浮かぶ別のソリューションです。

1
david a.

これは、さまざまなバージョンをログファイルに出力するために行います。拡張パスをハードコーディングしましたが、アプリは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();
}
0
Whome