CLOVER🍀

That was when it all began.

GreenPagesのMANIFEST.MFを読む

前回は、チュートリアルに従ってサンプルアプリケーションGreenPagesを、STSからVirgoを起動して動作させるところまでやりました。

今回は、GreenPages内の各アプリケーションのOSGi Bundleとしての関係を見ていこうと思います。インポートしたプロジェクトは

  • greenpages.web
  • greenpages.app
  • greenpages.jpa
  • greenpages.db

の4つなのですが、各プロジェクトの依存関係は、以下のようになっているそうです。

http://www.eclipse.org/virgo/documentation/virgo-documentation-2.1.1.RELEASE/docs/virgo-getting-started/html/ch03.html#installing.greenpages.introduction

webがフロントエンド、dbがDataSourceを提供…と見えるのですが、appとjpaは?jpaは名前的にJPAを使った機能を提供しそうですが。

とりあえず、OSGi BundleといえばMANIFEST.MFのようなので、各プロジェクトのMANIFEST.MFを見ていきましょう。

MANIFEST.MF from greenpages.web

Manifest-Version: 1.0
Import-Bundle: com.springsource.org.apache.taglibs.standard;version="[
 1.1.2,1.3)"
Bundle-Version: 2.3.0
Tool: Bundlor 1.0.0.RELEASE
Bundle-Name: GreenPages Web
Import-Library: org.springframework.spring;version="[3.0, 3.1)"
Bundle-ManifestVersion: 2
Bundle-SymbolicName: greenpages.web
Web-ContextPath: greenpages
Import-Package: freemarker.cache;version="[2.3.15,2.3.15]",greenpages;
 version="[2.3, 2.4)",javax.servlet.jsp.jstl.core;version="[1.1.2,1.2.
 0)",javax.sql,org.apache.commons.dbcp,org.eclipse.virgo.web.dm;versio
 n="[2.0.0, 3.0.0)",org.springframework.beans.factory.annotation;versi
 on="[3.0, 3.1)",org.springframework.core.io;version="[3.0, 3.1)",org.
 springframework.stereotype;version="[3.0, 3.1)",org.springframework.w
 eb.bind.annotation;version="[3.0, 3.1)",org.springframework.web.conte
 xt;version="[3.0, 3.1)",org.springframework.web.servlet;version="[3.0
 , 3.1)",org.springframework.web.servlet.mvc.annotation;version="[3.0,
  3.1)",org.springframework.web.servlet.view.freemarker;version="[3.0,
  3.1)"

MANIFEST.MF from greenpages.app

Manifest-Version: 1.0
Export-Package: greenpages;version="2.3.0"
Bundle-Vendor: SpringSource Inc.
Bundle-Version: 2.3.0
Tool: Bundlor 1.0.0.RELEASE
Bundle-Name: GreenPages Service
Bundle-ManifestVersion: 2
Bundle-SymbolicName: greenpages
Import-Package: org.springframework.stereotype;version="[3.0, 3.1)"

MANIFEST.MF from greenpages.jpa

Manifest-Version: 1.0
Import-Bundle: com.springsource.org.eclipse.persistence;version="[1.0.
 0, 1.0.0]",com.springsource.org.eclipse.persistence.jpa;version="[1.0
 .0, 1.0.0]"
Bundle-Vendor: SpringSource Inc.
Bundle-Version: 2.3.0
Tool: Bundlor 1.0.0.RELEASE
Bundle-Name: GreenPages JPA
Bundle-ManifestVersion: 2
Bundle-SymbolicName: greenpages.jpa
Import-Package: greenpages;version="[2.3, 2.4)",javax.persistence;vers
 ion="[1.0.0, 1.0.0]",javax.sql;version="0",org.apache.commons.dbcp;ve
 rsion="[1.2.2.osgi, 1.2.2.osgi]",org.springframework.beans.factory.an
 notation;version="[3.0, 3.1)",org.springframework.context.weaving;ver
 sion="[3.0, 3.1)",org.springframework.core.io;version="[3.0, 3.1)",or
 g.springframework.dao.annotation;version="[3.0, 3.1)",org.springframe
 work.orm.jpa;version="[3.0, 3.1)",org.springframework.orm.jpa.vendor;
 version="[3.0, 3.1)",org.springframework.stereotype;version="[3.0, 3.
 1)",org.springframework.transaction.annotation;version="[3.0, 3.1)",o
 rg.springframework.transaction.aspectj;version="[3.0, 3.1)"

MANIFEST.MF from greenpages.db

Manifest-Version: 1.0
Bundle-Vendor: SpringSource Inc.
Bundle-Classpath: .
Bundle-Version: 2.3.0
Tool: Bundlor 1.0.0.RELEASE
Bundle-Name: GreenPages DataSource
Bundle-ManifestVersion: 2
Bundle-SymbolicName: greenpages.db
Import-Package: javax.sql;version="0",org.apache.commons.dbcp;version=
 "[1.2.2.osgi, 1.2.2.osgi]",org.h2;version="[1.0.71, 1.0.71]"

いろいろ書いてますが、OSGi Bundleが外部にパッケージを公開するためには、「Export-Package」と書いてパッケージ名を書いていき、他のOSGi Bundleがそれを参照するためには「Import-Package」と書かねばならないらしいです。この4つのプロジェクトの中で、パッケージをエクスポートしているのはgreenpages.appプロジェクトのみなので、これがやっぱり中心にいるっぽいですね。

なお、エクスポートしているパッケージは「greenpages」です。ちょっと同梱されているソースは…と。

$ cd $GREENPAGES_HOME/solution/greenpages.app 
$ find ./src -type f
./src/main/resources/META-INF/MANIFEST.MF
./src/main/resources/META-INF/spring/osgi-context.xml
./src/main/resources/META-INF/spring/module-context.xml
./src/main/java/greenpages/internal/DirectoryImpl.java
./src/main/java/greenpages/internal/ImmutableListing.java
./src/main/java/greenpages/Directory.java
./src/main/java/greenpages/Listing.java
// ./src/main/java/greenpages/Directory.java
public interface Directory {

// ./src/main/java/greenpages/Listing.java
public interface Listing {

// ./src/main/java/greenpages/internal/DirectoryImpl.java
public class DirectoryImpl implements Directory {

// ./src/main/java/greenpages/internal/ImmutableListing.java
final class ImmutableListing implements Listing {

へぇ、公開しているのはインターフェースだけですねぇ。greenpages.internalパッケージには実装しかない…ってことは、これでインターフェースと実装体を分離して、インターフェースパッケージだけエクスポートしようってこと?

続いて、greenpages.jpaプロジェクトを見てみます。

$ cd $GREENPAGES_HOME/solution/greenpages.jpa 
$ find ./src -type f
./src/test/resources/META-INF/spring/test-context.xml
./src/test/java/greenpages/jpa/TestDataPopulator.java
./src/test/java/greenpages/jpa/JpaDirectorySpringContextTests.java
./src/main/resources/META-INF/persistence.xml
./src/main/resources/META-INF/orm.xml
./src/main/resources/META-INF/MANIFEST.MF
./src/main/resources/META-INF/spring/osgi-context.xml
./src/main/resources/META-INF/spring/module-context.xml
./src/main/java/greenpages/jpa/JpaListing.java
./src/main/java/greenpages/jpa/JpaDirectory.java
// ./src/main/java/greenpages/jpa/JpaDirectory.java
final class JpaDirectory implements Directory {

// ./src/main/java/greenpages/jpa/JpaListing.java
public class JpaListing implements Listing {

greenpages.appでエクスポートしたインターフェースを実装してますねぇ…。そして「Import-Package」でgreenpagesパッケージをインポートしてます、と。

つまり、greenpages.appってWeb層以下のインターフェースを規定するためのOSGi Bundleってことかな?んで、greenpages.jpaはその実装体のひとつです、と。なお、greenpages.dbにはホントにDataSourceの定義しかなかったです…。

ということは、インターフェースをかっちり決めてエクスポートして、実装体の切り替えは各Bundle内のosgi-context.xmlやmodule-context.xmlに書いておいて、SpringのDIを使ってうまいこと依存性を注入っていうのがこのプロダクトのやりたいことなのかな?しかも依存性もバージョンを指定した上でやれますよっと。

この推測が合ってるかどうかちょっとまだ自信ないですが、なんかすごそうですねぇ。DIを見ていた時は、インターフェースと実装の分離といっても実装体と大差ないインターフェースが散らばるばっかりで、あんまり意味無いなぁと思っていたのですが、こういうモジュールレベルでキレイに分離されているとちょっと感動的です。

ただ、実装体は確かにエクスポートしてませんけど、それを使う時ってどうやってんのかなぁ?実装体のクラス自体に直接アクセスできないけど、あくまでインターフェースの型を見ているだけだからOKということでしょうか…。舞台裏の繋ぎ合わせの部分がちょっとまだわかりません。