基本环境和上篇文章中所用的环境相同。
我在这里只是挑出重点部分和我在编译中遇到的问题,更完整的信息请参考ODL wiki中的相关部分:https://wiki.opendaylight.org/view/GettingStarted:Pulling,_Hacking,_and_Pushing_All_the_Code_from_the_CLI
本文假设你会linux的基本使用,java环境已配置好,会git和ecipse的基本使用...
apt-get install maven pkg-config gcc make ant g++ git libboost-dev libcurl4-openssl-dev libjson0-dev libssl-dev unixodbc-dev xmlstarlet
其中maven是用来构建项目的,安装了maven后需要修改settings.xml,关于settings.xml在后面讲解maven的时候会讲解。
简单的方法是执行下面的命令:
cp -n ~/.m2/settings.xml{,.orig} ; \wget -q -O - https://raw.githubusercontent.com/opendaylight/odlparent/master/settings.xml > ~/.m2/settings.xml
更详细的请看wiki:
https://wiki.opendaylight.org/view/GettingStarted:Development_Environment_Setup#Edit_your_.7E.2F.m2.2Fsettings.xml
我们从odl的gerrit获取源代码,至于gerrit是什么可以不管他。进去之后会看到很多project,不过我们只对controller感兴趣,进入controller或会看到一个git地址:git clone https://git.opendaylight.org/gerrit/controller。由于我们只是clone代码,并不push代码,所以只需要用上面的命令匿名获取代码就行了。
cd进你想放代码的目录,然后运行下面的命令:git clone https://git.opendaylight.org/gerrit/controller,就会把odl的代码clone到本地了,代码有20多M(不包括.git),有时候速度很慢,请耐心等待。
由于我们需要编译 Lithium版本的odl,因此需要checkout到Lithium版本,执行下面的命令即可:
cd controller & git checkout stable/lithium
然后执行git status确定一下是否checkout到了lithium版本,如果输出如下信息说明正确:
On branch stable/lithium
Your branch is up-to-date with 'origin/stable/lithium'.
nothing to commit, working directory clean
确保前面settings.xml已经修改好。执行mvn clean install,然后静静等待编译完成就行了,由于需要在线下载依赖包(我的下载了300多M),所以速度有点慢,我用了1个多小时。上面的命令会编译执行test代码,所以速度会满很多,你可以使用mvn clean install -D skipTests来跳过测试代码的执行。
静静等待编译完成,现在你可以去喝一杯咖啡了。如果因为网络连接不好二编译失败的话再多试几遍就可以了。
大家可能会疑惑,编译的出来的jar包去哪里了?编译完了怎么运行呢?怎么才能像预编译版本那样使用karaf来运行odl?
关于第一个问题我们留在下面讲解maven的时候再说,下面我们来解决后两个问题。
下面的我就不多说了:
git clone https://git.opendaylight.org/gerrit/p/integration.git
cd integration mvn clean install -D skipTests
编译完成后执行下面命令,当然不要忘了修改./etc/org.apache.karaf.management.cfg:
cd distributions/karaf/target/assembly bin/karaf
前面编译odl的时候用的试maven,另外odl使用的是osgi框架。所以我们首先要弄清楚什么试maven和osgi。
Maven是基于项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的软件项目管理工具.......(剩下的自己去百度百科看或者去maven官网看)
我也是第一次接触maven,所以只是照抄了一些别人的文章。
我们先来说一下前面多次强调要修改的settings.xml文件,其实刚装好maven的后~/.m2下是没有settings.xml的文件的。再/etc/maven下有settings.xml的原型,大家可以自己将他复制到~/.m2目录下并修改。前者又被叫做全局配置,后者被称为用户配置。如果两者都存在,它们的内容将被合并,并且用户范围的settings.xml优先。
下面是settings.xml顶层元素的概览:
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository/>
<interactiveMode/>
<usePluginRegistry/>
<offline/>
<pluginGroups/>
<servers/>
<mirrors/>
<proxies/>
<profiles/>
<activeProfiles/>
</settings>
settings.xml中主要包括以下元素:
1.localRepository:表示Maven用来在本地储存信息的本地仓库的目录。默认是用户家目录下面的.m2/repository目录。
2.interactiveMode:表示是否使用交互模式,默认是true;如果设为false,那么当Maven需要用户进行输入的时候,它会使用一个默认值。
3.offline:表示是否离线,默认是false。这个属性表示在Maven进行项目编译和部署等操作时是否允许Maven进行联网来下载所需要的信息。
4.pluginGroups:在pluginGroups元素下面可以定义一系列的pluginGroup元素。表示当通过plugin的前缀来解析plugin的时候到哪里寻找。pluginGroup元素指定的是plugin的groupId。默认情况下,Maven会自动把org.apache.maven.plugins和org.codehaus.mojo添加到pluginGroups下。
5.proxies:其下面可以定义一系列的proxy子元素,表示Maven在进行联网时需要使用到的代理。当设置了多个代理的时候第一个标记active为true的代理将会被使用
6.servers:其下面可以定义一系列的server子元素,表示当需要连接到一个远程服务器的时候需要使用到的验证方式。这主要有username/password和privateKey/passphrase这两种方式
7.mirrors:用于定义一系列的远程仓库的镜像。我们可以在pom中定义一个下载工件的时候所使用的远程仓库。但是有时候这个远程仓库会比较忙,所以这个时候人们就想着给它创建镜像以缓解远程仓库的压力,也就是说会把对远程仓库的请求转换到对其镜像地址的请求。每个远程仓库都会有一个id,这样我们就可以创建自己的mirror来关联到该仓库,那么以后需要从远程仓库下载工件的时候Maven就可以从我们定义好的mirror站点来下载,这可以很好的缓解我们远程仓库的压力。在我们定义的mirror中每个远程仓库都只能有一个mirror与它关联,也就是说你不能同时配置多个mirror的mirrorOf指向同一个repositoryId。
8.profiles:用于指定一系列的profile。profile元素由activation、repositories、pluginRepositories和properties四个元素组成。当一个profile在settings.xml中是处于活动状态并且在pom.xml中定义了一个相同id的profile时,settings.xml中的profile会覆盖pom.xml中的profile。
profiles下面同样有很多标签:
(1)activation:这是profile中最重要的元素。跟pom.xml中的profile一样,settings.xml中的profile也可以在特定环境下改变一些值,而这些环境是通过activation元素来指定的
(2)properties:用于定义属性键值对的。当该profile是激活状态的时候,properties下面指定的属性都可以在pom.xml中使用。
(3)repositories:用于定义远程仓库的,当该profile是激活状态的时候,这里面定义的远程仓库将作为当前pom的远程仓库。
(4)pluginRepositories:在Maven中有两种类型的仓库,一种是存储工件的仓库,另一种就是存储plugin插件的仓库。pluginRepositories的定义和repositories的定义类似,它表示Maven在哪些地方可以找到所需要的插件。
9.activeProfiles:它包含一系列的activeProfile元素,每个都有一个profile id的值,任何profile id被定义到activeProfile的profile将被激活,不管其他的环境设置怎么样。如果没有匹配的profile被找到,那么就什么事情也不做。
下面我们看一下odl的settings.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!-- vi: set et smarttab sw=2 tabstop=2: -->
<!--
Copyright (c) 2014, 2015 Cisco Systems, Inc. and others. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v1.0 which accompanies this distribution,
and is available at http://www.eclipse.org/legal/epl-v10.html
-->
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<profiles>
<profile>
<id>opendaylight-release</id>
<repositories>
<repository>
<id>opendaylight-mirror</id>
<name>opendaylight-mirror</name>
<url>http://nexus.opendaylight.org/content/repositories/public/</url>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>opendaylight-mirror</id>
<name>opendaylight-mirror</name>
<url>http://nexus.opendaylight.org/content/repositories/public/</url>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
<profile>
<id>opendaylight-snapshots</id>
<repositories>
<repository>
<id>opendaylight-snapshot</id>
<name>opendaylight-snapshot</name>
<url>http://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>opendaylight-snapshot</id>
<name>opendaylight-snapshot</name>
<url>http://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>opendaylight-release</activeProfile>
<activeProfile>opendaylight-snapshots</activeProfile>
</activeProfiles>
</settings>
另外这个settings.xml中另一个重要的标签是activeProfiles标签,可以看到对于opendaylight-release和opendaylight-snapshots这两个profile无论何时都处于激活状态。
.~/m2/repository 目录为 maven 的本地仓库,观察 mvn clean install 执行时,会发现有很多 download 的过程,download 下的内容即保存到了 repository 下的对应目录下了。从目前的经验来看,安装到这个仓库的内容包括执行 mvn命令时需要的或 pom.xml 所依赖的各种插件。按照 maven 的一些资料所述,一个 maven 构件若想能被其他 maven 项目使用,则需要将此构建安装到本地仓库中。上面执行mvn clean install的时候就将odl编译完成的jar和pom等文件安装到了~/m2/repository/org/opendaylight目录下。可以看到该目录下有很多编译好的与odl相关的文件,包括jar包,pom文件和一些其他文件。
maven 的主要命令包括: mvn clean compile、 mvn clean test、 mvn clean package、mvn clean install。Clean 是清空,compile 是编译,test 是编译 java 的 test 代码,
package 是打包,打包默认存放路径是 target/目录,install 是将打包出的.jar 安装到 maven 的本地仓库中,默认为 home 目录下的.m2/repository。根据我们使用mvn clean install 的经验,install 之前,会先执行 clean,compile 和 package,执行这些命令时实际上我们是在执行相应的 maven 插件。
注:以下部分摘自《Opendaylight学习及开发初级教程北邮-天依》
pom.xml 的开头的最重要的是 “groupId”, “artifactId” 和“version” 三行。这三个元素定义了一个项目基本的坐标,在 Maven 的世界,任何的 jar、 pom或者 war 都是以基于这些基本的坐标进行区分的。
以./controller/opendaylight/adsal/arphandler/下的pom.xml为例
<?xml version="1.0" encoding="UTF-8"?>
<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>
<parent>
<groupId>org.opendaylight.controller</groupId>
<artifactId>commons.opendaylight</artifactId>
<version>1.5.1-SNAPSHOT</version>
<relativePath>../../commons/opendaylight</relativePath>
</parent>
<artifactId>arphandler</artifactId>
<version>0.6.1-SNAPSHOT</version>
<packaging>bundle</packaging>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>clustering.services</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>connectionmanager</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>hosttracker</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal.connection</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>switchmanager</artifactId>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>topologymanager</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Import-Package>org.opendaylight.controller.sal.packet.address,
org.opendaylight.controller.connectionmanager,
org.opendaylight.controller.sal.connection,
org.opendaylight.controller.sal.core,
org.opendaylight.controller.sal.utils,
org.opendaylight.controller.sal.packet,
org.opendaylight.controller.sal.routing,
org.opendaylight.controller.switchmanager,
org.opendaylight.controller.topologymanager,
org.opendaylight.controller.clustering.services,
org.opendaylight.controller.hosttracker,
org.opendaylight.controller.hosttracker.hostAware,
org.apache.felix.dm,
org.osgi.service.component,
org.slf4j</Import-Package>
<Export-Package>org.opendaylight.controller.arphandler</Export-Package>
<Bundle-Activator>org.opendaylight.controller.arphandler.internal.Activator</Bundle-Activator>
</instructions>
<manifestLocation>${project.basedir}/META-INF</manifestLocation>
</configuration>
</plugin>
</plugins>
</build>
<scm>
<connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
<developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
<tag>HEAD</tag>
<url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
</scm>
</project>
GroupId 定义了项目属于哪个组,这个组往往和项目所在的组织或公司存在关联,譬如你在 googlecode 上建立了一个名为 myapp 的项目,那么 groupId 就应该是 com.googlecode.myapp,如果你 的公 司是 mycom ,有 一个 项目 为 myapp , 那么 groupId 就应 该是com.mycom.myapp。
ArtifactId 定义了当前 Maven 项目在组中唯一的 ID。顾名思义,version 指定了项目当前的版本随着项目的发展,version 会不断更新。“packaging”指的是打包方式,bundle 指打包成 bundle、 pom 指不打包、jar指打包成jar。 “build”是跟构建相关的设臵。“plugin”中的 maven-bundle-plugin 指 arphandler 要通过maven 的 maven-bundle-plugin 插件编译成 OSGI 的 bundle。“plugin”里的内容将在介绍 OSGI 时再介绍“dependencies”即依赖关系,但我没研究过依赖的机制(如何确定依赖)。
最后要提的是 maven 的一个重要概念,archetype。一般 maven 项目的根目录下会创建pom.xml,src/main/java 中为项目主代码,src/test/java 为执行单元测试的代码,有些工程还会有 resource 目录,以上目录都统称为项目骨架。每件一个 maven 项目都要建立那些目录,为了尽量减少重复工作,maven 提供了 mvnarchetype:generate 命令(maven 3.0 可以直接执行此命令),其中“archetype”指我们使用的是 maven-archetype-plugin 插件,“generate”指我们的目标是产生项目骨架。执行 mvn archetype:generate 命令后,我们可以自己选择希望用的archetype,输入我们要创建项目的 groupId、artifactId、version、以及包名package 并确认,Archetype 插件将根据我们提供的信息创建项目骨架,因此archetype 类似于模板的概念。在 opendaylight controller 中使用的 maven archetyp为 odl maven archetypes, Controller 代码中有一个对应的 archetypes 目录,其官网对 archetype 的介绍为“A maven archetype to create a yang model project that will generate java code from .yang files”,我认为研究这个 archetype 关系到我们将来如何在 opendaylight 写应用,因此很重要。
OSGI(Open Services Gateway Initiative),或者通俗点说JAVA动态模块系统,定义了一套模块应用开发的框架。OSGI容器实现方案如Knopflerfish, Equinox, and Apache Felix允许你把你的应用分成多个功能模块,这样通过依赖管理这些功能会更加方便。
OSGI规范包含两大块:一个OSGI容器需要实现的服务集合;一种OSGI容器和应用之间通信的机制。开发OSGI平台意味着你需要使用OSGI API编写你的应用,然后将其部署到OSGI容器中。从开发者的视角来看,OSGI提供以下优势:
只要你的应用完全符合OSGI规范,它就可以在所有符合OSGI规范的容器内运行。现在,有三种流行的开源OSGI容器:
下面我说一下OSGi中的重要概念:
注:以下部分摘自《Opendaylight学习及开发初级教程北邮-天依》
1. 每个 plug-in 工程都有一个 activator.java, 这是 bundle 启动时首先调用的程序入口,相当于 Java 模块中的 main 函数。不同的是,main 需要通过命令行调用,而 OSGI 的 Activator 是被动的接受 OSGI 框架的调用,收到消息后才开始启动。
2. Plug-in 工程中的另一个重要文件是 MANIFEST.MF。MANIFEST.MF 用来存储插件的配臵信息,包括这个插件的依赖, import-package, export-package等
opendaylight是基于OSGI的Maven工程。对于每一个odlbundle:
1.opendaylightcontroller有自己的mavenarchetype来生成bundle代码框架。
2.pom.xml配置maven-bundle-plugin插件可以实现maven根据用户配臵的instructions来自动生成plug-in中非常重要的MANIFEST.MF文件的内容。
3.配置pom.xml能指定maven将一个工程打包成bundle,指定<packaging>标签值为bundle,maven-assembly-plugin完成bundle的打包和部署。
下面是controller/opendaylight/arphandler的pom.xml中<plugin>标签的内容,
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Import-Package>org.opendaylight.controller.sal.packet.address,
org.opendaylight.controller.connectionmanager,
org.opendaylight.controller.sal.connection,
org.opendaylight.controller.sal.core,
org.opendaylight.controller.sal.utils,
org.opendaylight.controller.sal.packet,
org.opendaylight.controller.sal.routing,
org.opendaylight.controller.switchmanager,
org.opendaylight.controller.topologymanager,
org.opendaylight.controller.clustering.services,
org.opendaylight.controller.hosttracker,
org.opendaylight.controller.hosttracker.hostAware,
org.apache.felix.dm,
org.osgi.service.component,
org.slf4j</Import-Package>
<Export-Package>org.opendaylight.controller.arphandler</Export-Package>
<Bundle-Activator>org.opendaylight.controller.arphandler.internal.Activator</Bundle-Activator>
</instructions>
<manifestLocation>${project.basedir}/META-INF</manifestLocation>
</configuration>
</plugin>
</plugins>
关于导入eclipse,odl的wiki很详细,按照wiki来没问题。
eclipse需要安装一些插件才能导入odl,首先是m2e插件,eclipse luna以上版本自带,不需要另外安装,其他版本的eclipse请安装m2e插件:http://download.eclipse.org/technology/m2e/releases
ycho integration:http://repo1.maven.org/maven2/.m2e/connectors/m2eclipse-tycho/0.7.0/N/0.7.0.201309291400/
build-helper-maven plugin:
导入eclipse:
参考文章:
[1] https://wiki.opendaylight.org/view/GettingStarted:Pulling,_Hacking,_and_Pushing_All_the_Code_from_the_CLI
[2] https://wiki.opendaylight.org/view/GettingStarted:Development_Environment_Setup#Edit_your_.7E.2F.m2.2Fsettings.xml
[3] http://www.cnblogs.com/yakov/archive/2011/11/26/maven2_settings.html
[4] http://haohaoxuexi.iteye.com/blog/1827778
[5] http://www.sdnap.com/sdnap-post/4370.html
[6]http://longdick.iteye.com/blog/457310