0%

OSGi构建工具:Tycho还是Maven-Bundle-Plugin?

Tycho与Maven-Bundle-Plugin的对比

Maven与OSGi天生就是冤家:Maven通过pom.xml描述一个产物的全部,而OSGi将这项工作交给了MANIFEST.MF

如果仅仅是一些定义信息还好说,但是Maven和OSGi都希望能够描述产物的依赖关系,在使用Maven开发OSGi bundle的时候,就导致了一个问题:

依赖关系到底是在pom.xml中描述,还是在MANIFEST.MF中描述?

前面提到的Tycho的思路是由MANIFEST.MF自行管理bundle的依赖关系,pom.xml只记录使用maven进行构建时需要的信息,比如maven工程的父子关系、打包时需要的bundle仓库及要发布的目标平台等。

Tycho的这种机制对Eclipse IDE比较友好,在开发期间完全使用IDE的机制进行开发和调试,只有在打包部署时才依赖maven。

Apache Felix Maven-Bundle-Plugin
则使用另一套机制:使用Maven-Bundle-Plugin,在开发时可以没有MANIFEST.MF文件!Maven-Bundle-Plugin在pom.xml中复制了一套MANIFEST.MF的元数据,完全可以通过pom.xml文件中的定义生成出完整的MANIFEST.MF文件。

Maven-Bundle-Plugin的这种机制使得工程完全的”maven化”,更适合传统非OSGi开发人员的使用习惯。但是无法很好的利用IDE的开发和调试功能,比如,你可能需要自己搭建一个运行环境从IDE中调用。

两种方式可谓各有千秋。但是Tycho明显基于Equniox和Eclipse,比如,Tycho可以配置Eclipse p2站点作为bundle库。如果要使用Tycho开发和调试Felix,需要搭建一个Eclipse风格的p2站点,将Felix runtime和需要的各种bundle都放到该站点中并发布,然后在Tycho中引用该站点。更详细的说明可以参考这里

而Felix Maven-Bundle-Plugin对于各种OSGi runtime的支持是相同的,由于完全基于maven,使用任何IDE开发bundle的效果都差不多。通常,Felix系的平台,如Karaf、Geronimo、Camel、ServiceMix、Fuse等,其例子都是使用Maven-Bundle-Plugin构建的。

由于前文已经说明了如何用Tycho开发OSGi,下面只给出使用Maven-Bundle-Plugin的例子。

Maven-Bundle-Plugin的pom例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>thinkinside.demo.osgi</groupId>
<artifactId>simple-bundle</artifactId>
<version>0.0.1-SNAPSHOT</version>


<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<executions>
<execution>
<id>generate-resources</id>
<goals>
<goal>manifest</goal>
</goals>

<configuration>
<instructions>
<Bundle-Name>${project.name}</Bundle-Name>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Bundle-Activator>test.bundle.internal.Activator</Bundle-Activator>
<Export-Package>***</Export-Package>
<Import-Package>***</Import-Package>
<Private-Package>***</Private-Package>
</instructions>
</configuration>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.osgi.core</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
</project>

使用Maven-Bundle-Plugin构建bundle,就是构建一个简单的jar。不同之处在于:要通过pom.xml中的信息生成符合OSGi要求的MANIFEST.MF文件并打包到jar中。这通过两个插件来完成:

  • org.apache.felix:maven-bundle-plugin

    在项目生命周期的”generate-resources”阶段,根据<instructions>标签内定义的信息生成MANIFEST.MF文件。这里可以配置OSGi所需要的全部元数据。

  • org.apache.maven.plugins:maven-jar-plugin

    配置其在打包是使用前面生成的MANIFEST.MF文件

由于OSGi bundle通常会使用OSGi API,这里添加了org.apache.felix:org.osgi.core的依赖。当然也可以换成其他的OSGi运行时,比如Equinox。

此时,使用mvn package生成的jar包中,MANIFEST.MF文件内已经添加了配置好的bundle信息。

当然,使用maven-bundle-plugin的目标(Goals)
可以进行更细致的控制。

在Eclipse中运行和调试

本来,传说中的Pax Cursor可以在Eclipse中基于各种OSGi runtime运行和调试bundle,但是天朝的网络中似乎不存在ops4j.org这个域名。

好在我们可用一个Java Project的方式建立起Felix的环境,通过Eclipse对bundle进行运行和调试。
由于这里有非常详细的说明,故不再赘述。

其实,我们还可以基于maven构建,而不是使用Java Project的方式。使用maven的好处是这种方法可以用于任何支持maven的IDE。

Felix runtime的主要内容包括:

其中:

  • bin/felix.jar 启动的jar, MainClass是org.apache.felix.main.Main
  • bundle/ 存放可用的bundle,Felix runtime中内置了4个必需的bundle
  • conf/conf.properties 启动配置。类似于Eclipse的configuration/config.ini。Felix配置项可以参考官方网站中的内容

知道了Felix runtime的构成,就可以用maven构建出相同的结构,并插入到项目周期的适当位置。pom如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>thinkinside.demo.fuse</groupId>
<artifactId>felix-launcher</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Felix Launcher</name>
<properties>
<felix.bundlerepository.version>1.6.4</felix.bundlerepository.version>
<felix.gogo.version>0.10.0</felix.gogo.version>
<felix.framework.version>4.2.1</felix.framework.version>
</properties>

<build>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.4.1</version>
<configuration>
<filesets>
<fileset>
<directory>bundle</directory>
</fileset>
</filesets>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>copy</id>
<phase>generate-resources</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.gogo.command</artifactId>
<version>${felix.gogo.version}</version>
</artifactItem>
<artifactItem>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.gogo.runtime</artifactId>
<version>${felix.gogo.version}</version>
</artifactItem>
<artifactItem>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.gogo.shell</artifactId>
<version>${felix.gogo.version}</version>
</artifactItem>
<artifactItem>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.compendium</artifactId>
<version>4.2.0</version>
</artifactItem>
</artifactItems>
<outputDirectory>bundle</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>

</build>

<dependencies>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.main</artifactId>
<version>${felix.framework.version}</version>
</dependency>

<dependency>
<groupId>org.ops4j.pax.url</groupId>
<artifactId>pax-url-assembly</artifactId>
<version>1.6.0</version>
</dependency>
</dependencies>
</project>

该pom在标准的生命周期中增加了两项工作:

  • generate-resources阶段,创建bundle文件夹,复制必需的4个bundle
  • clean阶段,清除bundle文件夹

最后,还需要一个配置文件。在工程目录建立/conf/config.properties文件,并进行基本配置:

1
2
3
4
felix.auto.deploy.action=install,start
felix.log.level=1

org.osgi.framework.storage.clean=onFirstInit

配置完成了,先执行mvn compile生成需要的资源。此时使用命令mvn exec:java -Dexec.mainClass="org.apache.felix.main.Main"即可以启动Felix runtime:

在Eclipse中,将这个工程作为Java Application运行,选择org.apache.felix.main.Main作为Main Class,就可以进行运行和调试。