I. Définition de OSGi▲
OSGi (Open Service Gateway Initiative) est une spécification permettant de concevoir une application basée sur une architecture modulaire. Chaque module, appelé bundle. Il possède une version et peut dépendre d'autres modules. OSGi gère différents classloader par bundle. Ceci permet une gestion dynamique des bundles, donc de déployer plusieurs versions d'un même composant. Le redéploiement partiel et à chaud de composants est donc ainsi possible, ce qui permet une mise à jour de versions applicatives sans coupure de service.
II. Présentation de Karaf▲
Karaf est un framework open source de la fondation Apache, basé sur OSGi. La dernière version (4.0.3) est téléchargeable sur le site ici. Il faut ensuite se positionner dans le répertoire bin/ et lancer la commande : karaf. La console shell de Karaf présente alors un prompt qui permet de lancer des commandes :
Karaf s'appuie sur Apache Aries pour fournir un mécanisme d'injection de dépendances pour OSGi. Un bundle est constitué d'un fichier Blueprint XML qui permet d'instancier des composants, d'injecter des dépendances entre ces composants, d'exposer des services à travers le Service Registry, d'injecter des références vers d'autres services d'autres bundles.
2.
3.
4.
<?xml version="1.0" encoding="UTF-8"?>
<blueprint
xmlns
=
"http://www.osgi.org/xmlns/blueprint/v1.0.0"
>
...
</blueprint>
Le plugin maven maven-bundle-plugin va permettre de packager le bundle et de générer le fichier MANIFEST.MF définissant un nom Bundle-SymbolicName, une version Bundle-Version, les packages exportés Export-Package, et importés Import-Package, ou encore les packages contenant les commandes Karaf-Commands.
Un bundle peut être installé manuellement. Par exemple :
> bundle:install -s mvn:com.h2database/h2/1.4.190
Mais, il peut être également installé par l'intermédiaire d'une feature. Une feature est constituée d'un fichier description XML qui liste les bundles que l'on souhaite installer au démarrage.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
<features
name
=
"${project.artifactId}-${project.version}"
xmlns
=
"http://karaf.apache.org/xmlns/features/v1.3.0"
>
<feature
name
=
'${project.artifactId}'
description
=
'${project.name}'
version
=
'${project.version}'
>
<details>
${project.description}</details>
<feature
version
=
"4.0.3"
>
jdbc</feature>
<feature
version
=
"4.3.6.Final"
>
hibernate</feature>
<feature
version
=
"2.2.0"
>
jpa</feature>
...
<bundle
start-level
=
"70"
>
mvn:com.h2database/h2/1.4.190</bundle>
...
</feature>
</features>
Karaf vient avec un ensemble de repositories de features préconfigurées. Les commandes, ci-dessous, permettent respectivement de lister les repositories de features, lister les features, installées ou à disposition pour installation, installer une feature.
2.
3.
> feature:repo-list
> feature:list
> feature:install <nom_feature>
Les bundles sont récupérés depuis Internet et stockés dans le repository local. Les commandes, ci-dessous, permettent respectivement de démarrer/stopper un bundle, lister les bundles installés, de redéployer automatiquement un bundle compilé et installé dans le repository local.
2.
3.
4.
> bundle:start
> bundle:stop
> bundle:list
> bundle:watch <bundle_id>
III. Projet OSGi exemple▲
Le projet exemple ippon-osgi-sample montre comment développer des commandes OSGi. Il s'agit d'une application de type CRUD qui fournit la possibilité de lister les salariés de la société, d'ajouter, de mettre à jour et de supprimer un salarié d'une base de données. Cet exemple s'appuie sur un socle JPA/Hibernate et une base H2. Il est organisé en projet multimodules maven :
2.
3.
4.
5.
6.
+ippon-osgi-sample
|-ippon-osgi-sample-ds
|-ippon-osgi-sample-services
|-ippon-osgi-sample-command
|-ippon-osgi-sample-kar
|-ippon-osgi-sample-ittests
- ippon-osgi-sample-ds contient la datasource vers la base H2, packagée sous forme de bundle pour être déployé simplement.
- ippon-osgi-sample-services contient les services et entités JPA. Ces services sont exposés en tant que services OSGi.
- ippon-osgi-sample-command contient les commandes OSGi qui pourront être invoquées depuis le shell de Karaf.
- ippon-osgi-sample-kar contient principalement le fichier features.xml qui permet de faire du provisionning et de packager notre application avec les bundles précédents pour déploiement dans Karaf.
- ippon-osgi-sample-ittests contient les tests d'intégration d'exécution de nos commandes.
Pour initialiser le projet, on peut utiliser différents archetypes maven. Le premier est un archetype maven destiné à créer des commandes. Le second permet d'initialiser un projet avec Blueprint XML. Le troisième est un archetype maven pour la création de feature, pour le provisionning et le packaging sous forme de fichier kar.
2.
3.
4.
5.
$ mvn archetype:generate -DarchetypeGroupId=org.apache.karaf.archetypes -DarchetypeArtifactId=karaf-command-archetype -DarchetypeVersion=4.0.0 -DgroupId=fr.ippon.osgi.sample -DartifactId=ippon-osgi-sample-command -Dversion=1.0-SNAPSHOT -Dpackage=fr.ippon.osgi.sample.command
$ mvn archetype:generate -DarchetypeGroupId=org.apache.karaf.archetypes -DarchetypeArtifactId=karaf-blueprint-archetype -DarchetypeVersion=4.0.0 -DgroupId=fr.ippon.osgi.sample -DartifactId=ippon-osgi-sample-services -Dpackage=fr.ippon.osgi.sample.services -Dversion=1.0-SNAPSHOT
$ mvn archetype:generate -DarchetypeGroupId=org.apache.karaf.archetypes -DarchetypeArtifactId=karaf-feature-archetype -DarchetypeVersion=4.0.0 -DgroupId=fr.ippon.osgi.sample -DartifactId=ippon-osgi-sample-feature -Dversion=1.0-SNAPSHOT -Dpackage=fr.ippon.osgi.sample.feature
Une feature définit les différentes ressources via URL (instances, bundles, fichiers de configuration). features.xml recense d'autres features que l'on souhaite installer et activer par défaut au démarrage du serveur. Voici les principaux dans notre cas : jdbc, hibernate, transaction, jpa, etc. Dans ce même fichier peuvent être ajoutés nos propres bundles, par exemple, l'ajout du driver H2 ou des bibliothèques Apache Commons. La commande feature : info hibernate liste l'ensemble des bundles dépendant de cette feature. Karaf peut demander le téléchargement d'artefacts à partir de dépôts distants présents dans sa liste de repositories.
Un kar est donc un package sous forme d'archive zip, qui contient toutes les ressources décrites dans le fichier features XML. Il peut être déployé sans connexion Internet. il est constitué d'un répertoire repository contenant une liste de features XML et l'ensemble des artefacts Maven. Voici les commandes pour installer / désinstaller un kar :
2.
karaf@root()> kar:uninstall ippon-osgi-sample-kar-1.0-SNAPSHOT
karaf@root()> kar:install file:/D:/Java/workspace-nb/ippon-osgi-sample/ippon-osgi-sample-kar/target/ippon-osgi-sample-kar-1.0-SNAPSHOT.kar
III-A. Service JNDI pour la Datasource▲
Le projet ippon-osgi-sample-ds produit à la compilation un bundle OSGi qui va enregistrer dans le registre de services notre datasource vers la base H2. Ce service est accessible à partir de son nom JNDI (jdbc/ippon-osgi)
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
<blueprint
xmlns
=
"http://www.osgi.org/xmlns/blueprint/v1.0.0"
>
<bean
id
=
"dataSource"
class
=
"org.h2.jdbcx.JdbcDataSource"
>
<property
name
=
"URL"
value
=
"jdbc:h2:tcp://localhost/~/ippon-osgi;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS ippon"
/>
<property
name
=
"user"
value
=
"ippon"
/>
<property
name
=
"password"
value
=
"ippon"
/>
</bean>
<service
interface
=
"javax.sql.DataSource"
ref
=
"dataSource"
>
<service-properties>
<entry
key
=
"osgi.jndi.service.name"
value
=
"jdbc/ippon-osgi"
/>
</service-properties>
</service>
</blueprint>
III-B. Services et entités JPA▲
Le bundle ippon-osgi-sample-services contient les entités JPA et les services d'accès à la base de données. On définit le fichier persistence.xml en précisant bien l'URL vers le service qui expose la datasource.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
<persistence
version
=
"2.1"
xmlns
=
"http://xmlns.jcp.org/xml/ns/persistence"
xmlns
:
xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xsi
:
schemaLocation
=
"http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
>
<persistence-unit
name
=
"ippon-pu"
transaction-type
=
"JTA"
>
<provider>
org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>
fr.ippon.osgi.sample.model.Employee</class>
<exclude-unlisted-classes>
true</exclude-unlisted-classes>
<jta-data-source>
osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=jdbc/ippon-osgi)</jta-data-source>
<properties>
<property
name
=
"hibernate.dialect"
value
=
"org.hibernate.dialect.H2Dialect"
/>
...
</properties>
</persistence-unit>
</persistence>
Dans le fichier Blueprint XML, JPA est activé. Les beans de services sont déclarés et exposés comme services OSGi, afin de les utiliser dans d'autres bundles.
2.
3.
4.
5.
6.
7.
8.
9.
10.
<blueprint
xmlns
=
"http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns
:
xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns
:
jpa
=
"http://aries.apache.org/xmlns/jpa/v2.0.0"
xmlns
:
tx
=
"http://aries.apache.org/xmlns/transactions/v1.2.0"
default-activation
=
"lazy"
>
<
jpa
:
enable />
<bean
id
=
"employeeBean"
class
=
"fr.ippon.osgi.sample.services.EmployeeServiceImpl"
>
<
tx
:
transaction
method
=
"*"
/>
</bean>
<service
ref
=
"employeeBean"
interface
=
"fr.ippon.osgi.sample.services.EmployeeService"
/>
</blueprint>
Il ne faut pas oublier aussi de préciser au niveau du plugin maven-bundle-plugin le chemin vers le fichier de configuration JPA <Meta-Persistence>META-INF/persistence.xml</Meta-Persistence> et d'exporter les packages contenant les services <Export-Package>fr.ippon.osgi.sample.services*</Export-Package>.
La configuration JPA est classique. Une entityManager est récupérée grâce à l'annotation @PersistenceContext(unitName = "ippon-pu") et l'API Criteria JPA est utilisée pour construire les requêtes. (cf. EmployeeServiceImpl.java.)
III-C. Développement de commandes Karaf▲
Karaf offre la possibilité d'étendre ses commandes shell de base. Nous allons créer nos propres commandes faisant référence à nos services Blueprint développés précédemment dans le bundle ippon-osgi-sample-services. Une commande est définie par un scope et un nom. Elle peut avoir en paramètre des options ou des arguments ; la complétion peut être activée.
Voici un exemple de commande faisant appel au service qui liste les salariés de la société.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
@Command
(
scope =
"ippon"
, name =
"list-employees"
, description =
"Liste les employees de la societe"
)
@Service
public
class
ListEmployees implements
Action {
@Option
(
name =
"-j"
, aliases =
{
"--job"
}
, description =
"Liste de jobs"
, required =
false
, multiValued =
false
)
@Completion
(
JobCompleter.class
)
private
String jobsParam;
@Reference
private
EmployeeService employeeService;
@Override
public
Object execute
(
) throws
Exception {
System.out.println
(
"Liste des employes :"
);
employeeService.getAllEmployees
(
);
...
}
}
Les annotations @Command @Service servent à déclarer cette classe comme commande Karaf. Cette commande est exposée comme un service OSGi. Il faut également dans le maven-bundle-plugin penser à définir les packages contenant les commandes Karaf <Karaf-Commands>fr.ippon.osgi.sample.command*</Karaf-Commands> dans les instructions.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
<plugin>
<groupId>
org.apache.felix</groupId>
<artifactId>
maven-bundle-plugin</artifactId>
<version>
2.5.4</version>
<extensions>
true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>
${project.artifactId}</Bundle-SymbolicName>
<Export-Package>
fr.ippon.osgi.sample.command*;-noimport:=true
</Export-Package>
<Karaf-Commands>
fr.ippon.osgi.sample.command*</Karaf-Commands>
</instructions>
</configuration>
</plugin>
L'annotation @Option permet de définir des paramètres pour la commande. @Argument permet de définir les arguments. @Completion permet de faire de la complétion et peut être associée à une option ou un argument de commande.
L'annotation @Reference permet de récupérer les services OSGi exposés par le projet ippon-osgi-services. L'usage de ces annotations simplifie grandement la configuration, réalisée auparavant en XML dans les versions antérieures de Karaf (dans le fichier Blueprint XML du bundle). La méthode execute() contient le cœur d'exécution de la commande qui renvoie la liste des salariés.
Retourner tous les salariés de la société : ippon:list-employees
Retourner uniquement les architectes de la société : ippon:list-employees -j ARCHITECT
Retourner uniquement les architectes de la société dont le nom contient 'Employee 3': ippon:list-employees -j ARCHITECT -n 'Employee 3'
D'autres commandes d'ajout et de suppression de salarié sont disponibles sur GitHub ici.
2.
> ippon:add-employee DEV 'New Employee' 'New Employee' '01-01-1990'
> ippon:remove-employee 2
III-D. Packaging kar▲
Voici le feature du projet, il contient les features Karaf à activer, les bundles de bibliothèques tierces et les bundles du projet (ippon-osgi-sample-*). Le plugin maven karaf-maven-plugin va générer le kar (cf. pom.xml).
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
<features
name
=
"${project.artifactId}-${project.version}"
xmlns
=
"http://karaf.apache.org/xmlns/features/v1.3.0"
>
<feature
name
=
'${project.artifactId}'
description
=
'${project.name}'
version
=
'${project.version}'
>
<details>
${project.description}</details>
<feature
version
=
"4.0.3"
>
jdbc</feature>
<feature
version
=
"4.3.6.Final"
>
hibernate</feature>
<feature
version
=
"2.2.0"
>
jpa</feature>
<feature
version
=
"1.3.0"
>
transaction</feature>
<feature
version
=
"4.0.3"
>
jndi</feature>
<bundle
start-level
=
"70"
>
mvn:com.h2database/h2/1.4.190</bundle>
<bundle
start-level
=
"80"
>
mvn:commons-lang/commons-lang/2.6</bundle>
<bundle
start-level
=
"80"
>
mvn:commons-logging/commons-logging/1.2</bundle>
<bundle
start-level
=
"80"
>
mvn:commons-io/commons-io/2.4</bundle>
<bundle
start-level
=
"80"
>
mvn:fr.ippon.osgi.sample/ippon-osgi-sample-ds/1.0-SNAPSHOT</bundle>
<bundle
start-level
=
"80"
>
mvn:fr.ippon.osgi.sample/ippon-osgi-sample-services/1.0-SNAPSHOT</bundle>
<bundle
start-level
=
"80"
>
mvn:fr.ippon.osgi.sample/ippon-osgi-sample-command/1.0-SNAPSHOT</bundle>
</feature>
</features>
III-E. Tests d'intégration des commandes avec PaxExam▲
PaxExam est un framework pouvant réaliser des tests d'intégration dans le cadre d'un environnement OSGi. Il est capable de démarrer un Karaf, de déployer des features, des bundles, de surcharger les propriétés de configuration et de lancer de commandes. Différentes stratégies permettent d'utiliser ou non la même configuration pour chaque test unitaire.
Pour l'intégrer au projet Maven ippon-osgi-sample-ittests, il faut ajouter les dépendances suivantes :
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.
<dependency>
<groupId>
org.ops4j.pax.exam</groupId>
<artifactId>
pax-exam-container-karaf</artifactId>
<version>
${pax-exam.version}</version>
<scope>
test</scope>
</dependency>
<dependency>
<groupId>
org.ops4j.pax.exam</groupId>
<artifactId>
pax-exam-junit4</artifactId>
<version>
${pax-exam.version}</version>
<scope>
test</scope>
</dependency>
<dependency>
<groupId>
org.ops4j.pax.exam</groupId>
<artifactId>
pax-exam-inject</artifactId>
<version>
${pax-exam.version}</version>
<scope>
test</scope>
</dependency>
<dependency>
<groupId>
org.apache.geronimo.specs</groupId>
<artifactId>
geronimo-atinject_1.0_spec</artifactId>
<version>
1.0</version>
<scope>
test</scope>
</dependency>
<!-- Karaf -->
<dependency>
<groupId>
org.apache.karaf</groupId>
<artifactId>
apache-karaf</artifactId>
<version>
4.0.3</version>
<type>
tar.gz</type>
<scope>
test</scope>
<exclusions>
<exclusion>
<groupId>
org.apache.karaf</groupId>
<artifactId>
org.apache.karaf.client</artifactId>
</exclusion>
</exclusions>
</dependency>
Puis ajouter le plugin suivant, pour activer les fonctionnalités de versionAsInProject() sur les features (voir plus loin).
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
<plugin>
<groupId>
org.apache.servicemix.tooling</groupId>
<artifactId>
depends-maven-plugin</artifactId>
<version>
1.2</version>
<executions>
<execution>
<id>
generate-depends-file</id>
<goals>
<goal>
generate-depends-file</goal>
</goals>
</execution>
</executions>
</plugin>
La classe de tests d'intégration des commandes Karaf doit posséder les annotations suivantes : @RunWith(PaxExam.class) pour activer PaxExam et @ExamReactorStrategy(PerClass.class) pour activer la configuration une et une seule fois pour tous les tests de cette même classe. La classe étendue KarafTestSupport fournit des fonctions permettant d'exécuter des commandes, vérifier l'installation d'un bundle ou d'une feature. Elle est fortement inspirée de celle des tests d'intégration du projet Karaf lui-même. https://github.com/apache/karaf/blob/master/itests/src/test/java/org/apache/karaf/itests/KarafTestSupport.java
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.
@RunWith
(
PaxExam.class
)
@ExamReactorStrategy
(
PerClass.class
)
public
class
IpponOSGIPaxExamTest extends
KarafTestSupport {
@ProbeBuilder
public
TestProbeBuilder probeConfiguration
(
TestProbeBuilder probe) {
return
probe.setHeader
(
Constants.DYNAMICIMPORT_PACKAGE, "*,org.apache.felix.service.*;status=provisional"
);
}
@Configuration
public
static
Option[] configure
(
) throws
Exception {
return
new
Option[]{
karafDistributionConfiguration
(
)
.frameworkUrl
(
"mvn:org.apache.karaf/apache-karaf/4.0.3/tar.gz"
)
.karafVersion
(
"4.0.3"
)
.useDeployFolder
(
false
)
.unpackDirectory
(
new
File
(
"target/paxexam/unpack"
)),
logLevel
(
LogLevelOption.LogLevel.WARN),
// install features
features
(
maven
(
).groupId
(
"org.apache.karaf.features"
).artifactId
(
"standard"
).type
(
"xml"
).classifier
(
"features"
).versionAsInProject
(
), "jdbc"
),
features
(
maven
(
).groupId
(
"org.apache.karaf.features"
).artifactId
(
"standard"
).type
(
"xml"
).classifier
(
"features"
).versionAsInProject
(
), "hibernate"
),
features
(
maven
(
).groupId
(
"org.apache.karaf.features"
).artifactId
(
"standard"
).type
(
"xml"
).classifier
(
"features"
).versionAsInProject
(
), "jpa"
),
features
(
maven
(
).groupId
(
"org.apache.karaf.features"
).artifactId
(
"standard"
).type
(
"xml"
).classifier
(
"features"
).versionAsInProject
(
), "transaction"
),
features
(
maven
(
).groupId
(
"org.apache.karaf.features"
).artifactId
(
"standard"
).type
(
"xml"
).classifier
(
"features"
).versionAsInProject
(
), "jndi"
),
features
(
maven
(
).groupId
(
"org.apache.karaf.features"
).artifactId
(
"standard"
).type
(
"xml"
).classifier
(
"features"
).versionAsInProject
(
), "pax-jdbc-pool-dbcp2"
),
features
(
maven
(
).groupId
(
"org.apache.karaf.features"
).artifactId
(
"standard"
).type
(
"xml"
).classifier
(
"features"
).versionAsInProject
(
), "aries-annotation"
),
// Change ssh port
editConfigurationFilePut
(
"etc/org.apache.karaf.management.cfg"
, "rmiRegistryPort"
, RMI_REG_PORT),
editConfigurationFilePut
(
"etc/org.apache.karaf.management.cfg"
, "rmiServerPort"
, RMI_SERVER_PORT),
keepRuntimeFolder
(
),
// install bundles
mavenBundle
(
).groupId
(
"com.h2database"
).artifactId
(
"h2"
).version
(
"1.4.190"
),
mavenBundle
(
).groupId
(
"commons-lang"
).artifactId
(
"commons-lang"
).version
(
"2.6"
),
mavenBundle
(
).groupId
(
"commons-logging"
).artifactId
(
"commons-logging"
).version
(
"1.2"
),
mavenBundle
(
).groupId
(
"commons-io"
).artifactId
(
"commons-io"
).version
(
"2.4"
),
// install bundle datasource h2 for test
streamBundle
(
bundle
(
).add
(
"OSGI-INF/blueprint/datasource-h2-test.xml"
,
new
File
(
"src/test/resources/OSGI-INF/blueprint/datasource-h2-test.xml"
).toURL
(
))
.set
(
Constants.BUNDLE_NAME, "Apache Karaf :: Ippon OSGI Datasource Test"
)
.set
(
Constants.BUNDLE_SYMBOLICNAME, "ippon-osgi-sample-ds"
)
.set
(
"Bundle-ManifestVersion"
, "2"
)
.set
(
Constants.DYNAMICIMPORT_PACKAGE, "*"
).build
(
)).start
(
),
// install ippon bundles
mavenBundle
(
).groupId
(
"fr.ippon.osgi.sample"
).artifactId
(
"ippon-osgi-sample-services"
).version
(
"1.0-SNAPSHOT"
),
mavenBundle
(
).groupId
(
"fr.ippon.osgi.sample"
).artifactId
(
"ippon-osgi-sample-command"
).version
(
"1.0-SNAPSHOT"
),
}
;
}
...
}
La configuration dans la méthode probeConfiguration() autorise l'import dynamique de tous les packages de type provisional dans le features.xml du projet.
La configuration de la méthode configure() définit la distribution Karaf karafDistributionConfiguration() à déployer lors des lancements des tests, les features features() et bundles mavenBundle() à installer. streamBundle() permet de créer un bundle à la volée à partir d'une autre datasource de test datasource-h2-test.xml. editConfigurationFilePut() permet de surcharger les fichiers de configuration du serveur.
Il est alors possible de tester l'installation des features et bundles.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
@Test
public
void
testProvisioning
(
) throws
Exception {
// Check that the features are installed
assertFeatureInstalled
(
"jdbc"
, "4.0.3"
);
assertFeatureInstalled
(
"hibernate"
, "4.3.6.Final"
);
assertFeatureInstalled
(
"jpa"
, "2.2.0"
);
// Check that the bundles are installed
assertBundleInstalled
(
"ippon-osgi-sample-services"
);
assertBundleInstalled
(
"ippon-osgi-sample-command"
);
}
De tester l'exécution de nos commandes Karaf. Exemple :
2.
3.
4.
5.
6.
7.
8.
@Test
public
void
testListEmployeesWithOptionsCommand
(
) {
Assert.assertNotNull
(
bundleContext);
String result =
executeCommand
(
"ippon:list-employees -j ARCHITECT -n 'Employee 3'"
);
System.out.println
(
"result : "
+
result);
Assert.assertNotNull
(
result);
}
IV. Conclusion▲
Nous avons vu comment écrire nos propres commandes Karaf, comment les tester avec PaxExam. J'espère que ce tutoriel peut constituer une première approche pour qui souhaite débuter avec les concepts d'OSGi.
Le code source de l'application est disponible sur GitHub : https://github.com/sfoubert/ippon-osgi-sample
V. Remerciements▲
Cet article a été publié avec l'aimable autorisation de Ippon technologies.
Nous tenons à remercier Claude Leloup pour sa relecture orthographique et Mikcael Baron pour la mise au gabarit.