Bonjour.
Je cherchais depuis quelque temps comment faire une web app modulaire avec OSGI.
le but étant de déployer dynamiquement des modules qui se retrouve automatiquement référencé dans l'application sans intervention.
Je suis tombé sur le blog de AYOMA WIJETHUNGA
Son exemple fut donc un point de départ.
Je n'ai pas cherché à faire quelque chose de beau, mais à mettre en place une architecture réutilisable.
Tout comme Ayoma je me suis basé sur Pax Web Whiteboard.
Mais j'ai cherché à n'écrire que le strict minimum en java. (on peut faire mieux)
Mon idée était donc d'utiliser osgi blueprint pour déployer des bundles faisant appel à Pax Whiteboard pour déclarer des servlets.
Ayoma l'a fait en full Java.
Un module minimal se résume donc à des classes servlets et un fichier blueprint.
Restait un point comment faire pour que la webapp ajoute dans son contexte les éléments permettant aux utilisateurs d'accéder au dit module.
Ayoma propose une solution via une API pour alimenter un menu.
Lorsqu’un module démarre, l'application le détecte et récupère les informations du menu de ce module pour les ajouter au menu principal.
J'ai donc cherché à faire de même en utilisant blueprint et en cherchant à généraliser le principe.
Mettre en place une mécanique qui permet à une webapp de définir un ou plusieurs API et à des modules de les implementer.
Pour cela le pattern whiteboard était tout désigné.
Le tout se résume donc à un petit ensemble de bundles.
modules-whiteboard le tableau blanc abstrait permettant à une webapp de partager des API
main-api définie une interface IModule et une classe MenuItem partagées entre la webapp main et les modules
Main un bundle qui démarre la webapp il s'agit d'un simple bundle contenant un servlet, mais aussi le lanceur du tableau blanc.
User un bundle avec 2 servlets
Message un bundle avec 4 servlets.
Pour faciliter le dev, j'utilise maven et maven-bundle-plugin
s'ajoutent donc deux projets parents
pour tester la solution j'ai déployé servicemix 6.1.2 (Karaf 3.0.7 est suffisant)
Code text : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 parent module-whiteboard main-api modules main user message
le projet parentIci rien de bien compliqué. Seul point particulier la présence de la propriété web.context qui est utilisée pour définir le webcontext dans le bundle main, mais qui sera utilisé dans les autres.
Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
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 <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>fr.sekaijin.osgi.web</groupId> <artifactId>parent</artifactId> <version>0.0.1</version> <packaging>pom</packaging> <name>Sekaijin :: Web :: Parent</name> <modules> <module>main-api</module> <module>modules</module> <module>module-whiteboard</module> </modules> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> <slf4j.version>1.6.1</slf4j.version> <web.context>osgi</web.context> </properties> <dependencies> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j.version}</version> </dependency> </dependencies> </project>
Pour rester dans les définitions purement maven le projet modules destinés à accueillir tous les modules.Là encore rien de particulier.
Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
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 <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>fr.sekaijin.osgi.web</groupId> <artifactId>parent</artifactId> <version>0.0.1</version> </parent> <artifactId>modules</artifactId> <packaging>pom</packaging> <name>Sekaijin :: Web :: Modules</name> <modules> <module>main</module> <module>user</module> <module>message</module> </modules> <dependencies> <dependency> <groupId>fr.sekaijin.osgi.web</groupId> <artifactId>main-api</artifactId> <version>0.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> </dependencies> </project>
Le projet main-api celui-ci n'est là que pour partager une classe et une interface.
Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
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 <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>fr.sekaijin.osgi.web</groupId> <artifactId>parent</artifactId> <version>0.0.1</version> </parent> <artifactId>main-api</artifactId> <packaging>bundle</packaging> <name>Sekaijin :: Web :: Main API</name> <build> <plugins> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <version>3.2.0</version> <extensions>true</extensions> <configuration> <supportedProjectTypes> <supportedProjectType>bundle</supportedProjectType> </supportedProjectTypes> <instructions> <Bundle-SymbolicName>${web.context}-${project.artifactId}</Bundle-SymbolicName> <Bundle-Name>${project.name}</Bundle-Name> </instructions> </configuration> </plugin> </plugins> </build> </project>
Code java : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 package fr.sekaijin.osgi.web.main.api; import java.util.List; public interface IModule { public String getModuleName(); public List<MenuItem> getMenuItems(); }Les modules vont déclarer des menus en implémentant l'interface et la webapp va pouvoir les utiliser.
Code java : Sélectionner tout - Visualiser dans une fenêtre à part
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 package fr.sekaijin.osgi.web.main.api; public class MenuItem { private String key; private String path; private String moduleName; private String icon; public MenuItem(String moduleName, String icon, String key, String path) { super(); this.moduleName= moduleName; this.icon = icon; this.key = key; this.path = path; } public String getModuleName() { return moduleName; } public void setModuleName(String moduleName) { this.moduleName = moduleName; } public String getIcon() { return icon; } public void setIcon(String icon) { this.icon = icon; } public MenuItem(String key) { super(); this.key = key; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } }
La suite dans le prochain post
A+JYT
PS: https://github.com/sekaijin/webapp.w...rd/tree/master
Partager