CLOVER🍀

That was when it all began.

依存OSGi Bundleのバージョンアップ

前回はWeb層のOSGi Bundleを追加し、Service層のOSGi Bundleを共有する、ということをしました。では、今度はこの状態にService層のOSGi Bundleをバージョンアップして追加してみましょう。

つまり、

Web Bundle[Ver1.0] ------------> Service Bundle[Ver1.0]
                         |  
Web Bundle[Ver1.1] ------|       Service Bundle[Ver1.1]

ということをするわけですね。この時、両方のWeb BundleはどっちのService Bundleを見るんでしょうね?

ちなみに、OSGi Web BundleのMANIFEST.MFのImport-Packageは以下のようになっていました。

Import-Package: my.service.bundle;version="[1.0,2.0)",

この[1.0,2.0)は、my.service.bundleパッケージのバージョン1.0以上2.0未満(1.0 <= my.service.bundle < 2.0)に依存するという定義だそうです。ですので、1.1のService層のOSGi Bundleとは連携できるはずです。

なお、1.0固定にするためには[1.0,1.0]と[]で囲うらしいです。

では、Web層同様にバージョン1.0のBundleをコピーしてバージョン1.1を作成。

$ cp -R my-service-bundle my-service-bundle1.1

前回同様にSTSにインポートして、pom.xmlを修正。

  <modelVersion>4.0.0</modelVersion>
  <groupId>my.service.bundle</groupId>
  <artifactId>my-service-bundle</artifactId>
  <version>1.1.0</version>
  <packaging>jar</packaging>

MANIFEST.MFを修正。

Manifest-Version: 1.0
Export-Package: my.service.bundle;version="1.1.0"
Bundle-Version: 1.1.0
Bundle-Name: My Service Bundle
Bundle-ManifestVersion: 2
Import-Package: org.springframework.stereotype;version="[3.0,3.1)"
Bundle-SymbolicName: my.service.bundle

「Bundle-Version」を上げるだけでなく、「Export-Package」に書かれたパッケージのバージョンも上げおきましょう。

あとはわかりやすくするために、Serviceが返却する文字列を変更しておきます。

package my.service.bundle.internal;

import java.util.concurrent.atomic.AtomicInteger;

import my.service.bundle.HelloService;

import org.springframework.stereotype.Service;

@Service("helloService")
public class HelloServiceImpl implements HelloService {
	private AtomicInteger counter = new AtomicInteger();
	
	@Override
	public String getVersion() {
		return "1.1";
	}

	@Override
	public int getCount() {
		return counter.incrementAndGet();
	}
}

getVersionが「1.1」を返すようにしました。

ここから先は、STSのVirgo管理ツールでやるとなんかわかりにくそうなので、VirgoのAdmin Consoleを利用することにしました。

まずは、各プロジェクトを「mvn package」でパッケージングします。。この時、Service、Webの順でやりましょう。また、WebのビルドはServiceのJARがないと失敗するので、(あんまりやりたくないのですが)Serviceの「mvn package」後に「mvn install」を実行して、ローカルリポジトリにインストールした後で実行するようにしてください。

ではコマンドラインでVirgoを起動します。

$ $VWS_HOME/bin/startup.sh -clean

Admin Consoleにアクセスしてみます。

当然ですが、まだ何もありません。

んじゃ、OSGi Bundleをデプロイしてみましょっか。って、やってみたら、いきなり失敗。何で?と調べてみたら、MANIFEST.MFがなんかこんなことになっていました…。

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: xxxxx
Build-Jdk: 1.6.0_24

ほぉ、こっちで作ったMANIFEST.MFが無視されておるね?Mavenの設定が必要そうな感じなので、ちょっと調べてpom.xmlに以下の設定を追加。こちらは、Service用の設定です。

	<build>
		<plugins>
			<plugin>
    			<groupId>org.apache.maven.plugins</groupId>
    			<artifactId>maven-jar-plugin</artifactId>
   			<configuration>
   				<archive>
    					<manifestFile>${basedir}/src/main/resources/META-INF/MANIFEST.MF</manifestFile>
     				</archive>
   			</configuration>
   		</plugin>
   	</plugins>
	</build>

なお、Web用だと以下のように書きます。

		<plugin>
			<artifactId>maven-war-plugin</artifactId>
			<version>2.1-beta-1</version>
			<configuration>
				<packagingExcludes>WEB-INF/lib/**</packagingExcludes>
				<archive>
    				<manifestFile>${basedir}/src/main/webapp/META-INF/MANIFEST.MF</manifestFile>
     			</archive>
			</configuration>
		</plugin>

これに気付くのに、かなりハマりました…。

で、無事全部デプロイ完了。以下のURLにアクセスして、問題なく動くことを確認しておきます。
http://localhost:8080/my-web-bundle/hello/index
http://localhost:8080/my-web-bundle11/hello/index

続いて、Service Bundleのバージョン1.1をデプロイ。つまりは、こうなりました。

では、再度画面にアクセスすると…


なんと、変わりません…。あれ〜、そうなの??

ここで、VirgoのAdmin Consoleで「my.service.bundle 1.0.0」を選んで「Refresh」を選択すると…


おお、バージョン1.1に上がりましたよ!!自動的にロードし直すって動きはしないみたいですね。あと、参照していたWeb Bundle自体も再作成されるみたい。Web側のカウンタが1に戻っています。

つまりは、こういう状態になりました。

Web Bundle[Ver1.0] ------|       Service Bundle[Ver1.0]
                         |  
Web Bundle[Ver1.1] ------------> Service Bundle[Ver1.1]

ちなみに、この状態で「my.service.bundle 1.1.0」をAdmin Console上で「Stop」を選択して画面にアクセスすると、応答が返ってこなくなりました。依存関係があるやつを、いきなり停止してはいけないみたいですね。

では、今度は「my.service.bundle 1.1.0」を「Uninstall」して、画面にアクセスすると…


おお、1.0を見るように戻りましたよ!

どうも、新しいバージョンのBundleをデプロイしただけでは稼働中のBundleの参照先が切り替わるわけではないみたいですね。明示的に「Refresh」なり「Uninstall」なりした時に、再作成される模様。そうなると、「Stop」の意味がちょっとわかりませんが。

それにしても、稼働中にバージョンアップ/ダウンができるので、ちょっと面白いですね。実際に開発で使うと、相当ハマるでしょうが…。