Maven搭配Ant,使构建过程更灵活

Maven使构建变得规范、简便,但在某些时候还是感觉Ant更容易控制,把两者结合起来使构建变得更加灵活。Maven所定义的构建模型,再加上一些Plugin的帮助,让我们每容易的实现两者的结合。下面看个例子。

一个例子

项目中遇到这样一个问题,程序要检查某种License,License的版本号在另外的配置文件中定义。基于安全考虑,最好把版本号在编译期就写到某个常量中,而不在运行期读取某配置文件。假设我们要把版本号写入到某个enum类型的常量里,之前我们可以准备它模块文件。所以基本的构建流程如下:

  • 准备源文件
    • 读取License版本号
    • 读取Java模版文件
    • 版本号替换
    • 生成Java源文件包含最新的版本号
  • 编译源文件
  • 测试
  • 打包

实现

先看如下的代码目录结构(所用代码都在Github上)。

Selection_003

  • ant_replace_license_version.xml是Maven将要调用的Ant脚本
  • ant-contrib-1.0b3.jar包含了很多ant的扩展,有很多非常Powerful的工具。在这个例子中我会使用loadfile, propertyregex等功能。
  • License.template是License.java的模板文件
  • pom.xml是maven脚本
  • version.h是一个C/C++的头文件,里面定义了VERSION

构建过程就是要把version.h里版本号取出,替换模板文件里的占位符,然后生成真正的License类,并放到包com.innoli.sample中,由App调用。

具体文件内容

version.h

License.template

ant_replace_license_version.xml

使用了ant-contrib的扩展,完成了读取、查找、替换、生成新的类文件等工作。

pom.xml

使用了exec-maven-plugin来调用ant脚本,也可以使用Apache Maven AntRun Plugin, 但它MS使用了很旧的ant。在process-resources阶段,生成License类。

 

编译

一切就是这么简单!

使用nexus unzip repository plugin实现Eclipse p2代码仓库

使用RCP的同学们应该都知道,p2仓库管理软件包的Layout和maven自身的不同的。当使用Export Product时, 就可以看到repository文件夹里,软件包的放置是完全不同的。

Sonatype Nexus OSS可以部署p2的proxy repository, 但不能部署host repository (当然可以出银子买Professional版). 如何在OSS版里实现呢?大家可以通过unzip repository plugin来实现。

原理

unzip repository plugin的工作原理就是:

  • 指定某个Host Repository做为目标仓库
  • 解压Host仓库里的Zip文件,形成可以访问的且保留了原压缩包中文件夹结构的Virtual仓库

利用这个功能,就间接的做出p2的仓库,主要步骤:

  • 含有p2 layout的仓库做成zip
  • 上传或安装到某Host Repository
  • 设置Virtual Repository并指向Host Repository

Plugin安装

点这下载unzip repository plugin bundle file. 解压到Nexus的Plugin文件夹中,重启Nexus Server。

 配置Virtual Repository

以Eclipse Nebula 1.0为例,配置Virtual Repository。

2014-04-17_20-55-38

Eclipse Nebula Project提供了很多SWT的高级控件,很好的补充了原有的控件集。但它自身的Repository一直处于Snapshot状态,所以经常变动,很容易把持续集成搞挂。我们就遇到了两次。

有了Unzip virtual repository,这个情况就可以改变了。先下载Nebula 1.0的zip包,上传至一个Host Repo里。

2014-04-18_11-56-01

 

再新建一个Virtual Repository,Provider选择为“Unzip Repository Template”.

2014-04-17_21-34-01

2014-04-17_21-34-31

再去查看Virtual Repo,就可以看到Zip文件被解开成p2 layout的文件夹了。

2014-04-18_12-20-51

使用Virtual Repository

在Target Platform中使用我们定义的Virtual Repository,和普通的p2 repository一样。

2014-04-18_12-23-43

总结

unzip repository plugin很大程度上提高了Nexus的灵活性,不单单只是支持Maven的layout,还可以支持p2或其他layout. 我们的项目也可以向Nexus提交Eclipse RCP的代码仓库。

好东西,与大伙分享!

让普通Java Library包含C/C++动态库

如何让Java Library包含C/C++的动态库而且实现正确加载呢?

在OSGi环境下,我们可以在MANIFEST.MF定义不同平台(操作系统,CPU架构)要加裁的动态库,然后OSGi Runtime会正确找到它们,我们主要在start()方法里用System.loadLibrary()就可以正确的加载。

可对于POJO Java Library则没有这些便利。如何做呢?最近看到用到一个库叫sqlite-jdbc,它有比较完整的实现方法。现在做个小归纳。

代码结构

把各个平台下的动态库分文件夹放在源代码文件夹里。这样动态库会和.class一起打包进*.jar里(当然你也可用Maven进行更精确的控制),同时便于我们后面用Class.getResourceAsStream()进行调用。

 

动态库的加载

在Java里使用C/C++动态库,都是为了配合native API,使native能正常使用,首先要使这些库能被正确的加载。但在jar里的动态库是不能被System.loadLibrary()正确加载的。所以基本思路就是把它们Extract到真正的文件系统中

下面是加载流程:

  1. 用户可以通过环境变量自己提供动态库。第一步检查有没有设置Jar所需的so环境变量,如果用就不加载Jar包内的。
  2. 如果没有,根据操作系统(System.getProperty(“os.name”))和CPU架构(System.getProperty(“os.arch”)),找到包里对应的库,准备把库拷贝到temporary folder(System.getProperty(“java.io.tmpdir”))中。
  3. 拷贝之前,检查目标目录中是否已有动态库,用MD5码进行比对。
  4. 如果MD5不相同或库不存在,使用getResourceAsStream的方法把库写到目标目录中。
  5. 对非Window系统,赋予”755″权限。
  6. 最后使用System.load()把该动态库加载到JVM Runtime中。

 

总结

这是一个比较完备的方法。有了这套方法,我们还可以结合AntMaven动态的编译C/C++的源码,再打包。MS可以写个库来做实现整个流程。 :grin:

 

About “Plug-in from Existing JAR Archives” kind projects in maven+tycho build

In Eclipse RCP project, you may need to create such kind of “Plug-in from Existing JAR Archives” projects, because you need to reuse non-OSGi jar, such as Google Guava, SLF4j and etc.

In our team, before we have to manually download the needed jar libs from website, then change build.properties, MANIFEST.MF. And of couse, these libraries should be uploaded to version control system (such as P4, Git), as others (as well as Jenkins) can sync to latest and build.

This approach has some defects:

  • Too much manual work and hard to maintain the dependencis.
  • 3rd party libs become more and more.

Here is a solution for that – using maven dependency:copy-dependencies to copy all needed libs.

tycho + maven

Tycho is a great maven plugin, which can help to do headless build for a Eclipse RCP project. It will analyze the dependencies in MANIFEST.MF and also in pom.xml. We can use the feature to define the 3rd party dependencies in pom.xml.

You can find more usefule information about tycho on Eclipse.com.

Define the needed libraries in pom.xml

Just as what a common maven project does, you can define the libraries you need in <dependencies> of pom.xml, such as,

Use maven-dependency-plugin:copy-dependencies to copy

Use the goal of maven-dependency-plugin:copy-dependencies to copy those jars to specific folder, such as,

The goal is defined at “initialize” phase.

Change MANIFEST.MF

With this pom.xml, you can do a manually build and retrieve the jars from maven repository. Then you need to put them into the bundle’s CLASSPATH and exported packages in MANIFEST.MF.

Summary

Using this way, you don’t need to worry about third party libraries in OSGi environment any more. All dependencies are defined in pom.xml. It’s very clean and clear. Of course, in real world, you need do more configuration in pom.xml (such as clean work) and an IDE environment integration.