Tutoriel pour développer et déployer un service web RESTFUL de base sous Eclipse et Karaf

Développement d'un RESTFUL Webservice sous Eclipse et déploiement dans KARAF

Développant, jusqu'à présent des web services REST sous Talent ESB, la curiosité m'est venue de voir comment on pouvait en créer sous Eclipse dans le but de pouvoir les déployer sous Karaf.

Après beaucoup de recherches sur Internet, je n'ai pas trouvé de tutoriel qui permettait d'en développer rapidement avec un minimum de code.

J'ai donc décidé de me lancer et après plusieurs jours d'essais, j'ai trouvé une solution dont je tenais à vous faire part pour vous faire gagner du temps. Ce tutoriel s'adresse aux développeurs expérimentant la programmation de Web Service RESTful destinés à être déployés sur un serveur d'application basé sur les spécifications OSGI et plus spécifiquement sur Karaf.

Avant cela, il convient de vous présenter les différentes architectures qui rentrent en jeu dans l'utilisation des RESTful Web Services puis nous verrons, par un exemple concret leur mise en œuvre à partir d'Eclipse.

Si vous souhaitez donner votre avis sur le contenu de cet article, exprimez votre opinion, profitez de cette discussion : 3 commentaires Donner une note à l'article (5)

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Qu'est-ce qu'un RESTful webservice ?

Les RESTful web services sont devenus de plus en plus populaires. Il s'agit de services basés sur l'architecture REST. Ce type de web service a pour avantages d'être plus léger, plus évolutif et plus facilement maintenable.

L'architecture REST est une architecture s'appuyant sur le protocole HTTP. Elle permet, via une URL, d'effectuer plusieurs types d'opérations sur une ressource.

Ces opérations (utilisant souvent les formats d'échange JSON et XML) sont les suivantes :

  • GET
    Cette opération permet de récupérer des informations ;
  • POST
    Elle permet de créer une nouvelle entité en fournissant cette nouvelle entité dans le corps de la requête au format JSON ou XML (par exemple) ;
  • PUT
    Elle permet de mettre à jour une entité par les informations fournies au format JSON ou XML (par exemple) dans le corps de la requête ;
  • DELETE
    Elle permet de supprimer une entité via un identifiant fourni en paramètre.

On peut envoyer une requête à un web service REST par utilisation d'un client REST.

À défaut de développer un tel client REST lors des phases de test de votre futur web service RESTRepresentational State Transfer, on peut utiliser des plugins qui s'installent au sein du navigateur Internet tels :

Il existe un plugin client REST pour la plupart des navigateurs.

Ces clients REST permettent de fournir, en paramètre, le format d'échange des données dans l'entête HTTP en indiquant le « content-type ». Par exemple, voici une capture d'écran de RESTClient :

Image non disponible

Afin d'accéder à un RESTful web service, il suffit de saisir une URL. Dans l'exemple que nous allons développer dans ce tutoriel, l'adresse de notre web service est la suivante : http://localhost:8181/cxf/olivier/Cette adressereprésente ce qu'on appelle le « endpoint » (point terminal) de notre web service.

À partir de ce endpoint, on pourra accéder aux ressources - customers ou orders - via les URL suivantes :

http://localhost:8181/cxf/olivier/customers/

ou

http://localhost:8181/cxf/olivier/orders/

Il suffit ensuite de choisir, dans le client REST, la méthode d'accès à la ressource (GET, POST, PUT, DELETE), de fournir éventuellement un identifiant dans l'URLUniform Resource Locator pour identifier l'entité à laquelle on souhaite accéder et/ou de fournir éventuellement le corps (body) du message que l'on souhaite transmettre (au format JSON ou XML par exemple - ce format dépend du header HTTP qu'on a renseigné).

II. Qu'est-ce que KARAF ?

Karaf est un serveur d'application basé sur les spécifications OSGIOpen Services Gateway Initiative. Ces spécifications définissent un modèle de développement dans lequel les applications sont composées de plusieurs composants. Ces spécifications permettent aux composants de cacher leur implémentation aux autres composants en communiquant à l'aide de services partagés entre tous les composants.

Karaf est composé, entre autres d'un module appelé « Blueprint ».

Blueprint fournit un framework d'injection de dépendances pour OSGIOpen Services Gateway Initiative et a été standardisé par l'alliance OSGIOpen Services Gateway Initiative. Il consiste à travailler avec la nature dynamique des composants OSGIOpen Services Gateway Initiative, où les services peuvent devenir disponibles ou indisponibles à n'importe quel moment.

Blueprint permet, via un container, de superviser l'état des composants dans le framework et d'accomplir des actions en fonction de leur état.

Un composant est considéré être un composant Blueprint à partir du moment où il contient un ou plusieurs fichiers XML Blueprint. Ces fichiers XML sont localisés sous le répertoire OSGI-INF/blueprint comme nous le verrons plus tard.

Dès que Blueprint a déterminé qu'un composant est un composant Blueprint, il crée un container Blueprint basé sur le nom de ce composant. Ce container Blueprint est responsable de :

  • parser les fichiers XML Blueprint ;
  • instancier les composants ;
  • relier les composants entre eux ;
  • enregistrer les services ;
  • chercher les références des autres services.

Pour plus d'informations sur Blueprint, voir le site officiel : http://aries.apache.org/modules/blueprint.html

Le site officiel de Apache Karaf est le suivant : http://karaf.apache.org/

Les avantages de OSGIOpen Services Gateway Initiative sont présentés sur le site officiel du consortium : http://www.osgi.org/Main/HomePage

III. Problématique

Maintenant que nous avons posé les bases du fonctionnement des architectures REST, OSGI et du fonctionnement de Karaf, il peut être intéressant de savoir comment développer un RESTful web service  en JAVA sous Eclipse avec un minimum de configuration et en gagnant donc un maximum de temps.

Nous utiliserons, pour cela, un archetype MAVEN ainsi que le framework de services open source « Apache CXF ». CXF aide à construire et développer des services en utilisant des API comme JAX-WS et JAX-RS. Dans notre cas, nous utiliserons JAX-RS.

Le but de ce projet est de créer une application simple de gestion de clients et de commandes.

IV. Configuration logicielle

Les logiciels utilisés dans ce tutoriel sont les suivants :

Eclipse Mars

Karaf 4.0.2

V. Configuration d'Eclipse et de MAVEN

  1. Il convient d'abord de configurer correctement le MAVEN embarqué dans Eclipse. Pour cela, allez dans Windows → Preferences → Maven → User Settings et vérifiez le répertoire qui apparaît dans la section « User Settings » (ci-dessous, « C:\Users\orozier\.m2\settings.xml »)

    Image non disponible
  2. Créez dans le répertoire « .m2 » (à adapter selon vos besoins) un fichier setting.xml et remplissez-le de la manière suivante :

    setting.xml
    Sélectionnez
    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.
    <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>${user.home}/.m2/repository</localRepository>
    <interactiveMode>true</interactiveMode>
    <usePluginRegistry>false</usePluginRegistry>
    <offline>false</offline>
    <pluginGroups/>
    <servers/>
    <proxies>
        <proxy>
            <id>1</id>
            <active>true</active>
            <protocol>http</protocol>
            <host>proxy.XXXXX</host> <!Écrire le nom de votre proxy-->
            <port>8080</port><!—Écrire le port de votre proxy-->
            <nonProxyHosts>localhost|127.0.0.1</nonProxyHosts>
            </proxy>
        <proxy>
            <id>2</id>
            <active>true</active>
            <protocol>https</protocol>
            <host>proxy.XXXXX</host><!Écrire le nom de votre proxy-->
            <port>8080</port><!—Écrire le port de votre proxy-->
            <nonProxyHosts>localhost|127.0.0.1</nonProxyHosts>
        </proxy>
    </proxies>
    <profiles/>
    <activeProfiles/>
    </settings>
    
  3. Afin de voir le repository de MAVEN dans Eclipse, allez dans le menu Windows → Show view →Other →Maven →Maven Repository.
    L'onglet « Maven Repositories » apparaît alors.

  4. Dans l'arborescence, allez dans « Global Repositories » et cliquez droit sur « central (https://repo.maven.apache.org/maven2) » et choisissez « Rebuild index »
Image non disponible

L'intégralité du repository Maven apparaît quelques instants plus tard, ce qui signifie que Maven est correctement configuré. Si ce n'est pas le cas, un fichier log est disponible sous le workspace d'Eclipse dans le répertoire « \.metadata\.plugins\org.eclipse.m2e.logback.configurator\ ».

VI. Création d'un nouveau projet Maven à l'aide de l'archetype karaf-blueprint

Nous avons vu, plus haut, que Karaf s'appuyait sur Blueprint. Nous allons donc chercher un archetype MAVEN adapté à Blueprint afin de nous éviter des efforts de configuration. Nous n'aurons donc plus qu'à adapter le fichier XMLeXtensible Markup Language de Blueprint selon nos besoins.

  1. File → New → Maven Project

    Image non disponible
  2. Sur la fenêtre qui s'affiche, cliquez sur le bouton « Next »

    Image non disponible
  3. Dans le champ « Filter », saisissez « blueprint » puis, dans la liste qui apparaît, choisissez la ligne correspondant à « karaf-blueprint-archetype » puis cliquez sur le bouton « Next »

    Image non disponible
  4. Renseignez la fenêtre qui apparaît de cette manière :
    Group ID : RestFull_Webservice_Karaf
    Artefact Id : TestRestServiceKaraf
    Version : 0.0.1-SNAPSHOT
    Dans la section « Properties available from archetype », attribuez la valeur « RestFull_Webservice_Karaf.TestRestServiceKaraf ».
    Puis cliquez sur le bouton « Finish ».

  5. Un nouveau projet est créé dans l'explorateur de projets d'Eclipse :

    Image non disponible
  6. Renommez l'interface « MyService » et la classe « MyServiceImpl » via un clic droit →« Refactor » → « Rename » respectivement en « CustomerService » et « CustomerServiceImpl ».
    Le fichier CustomerSerice.java contient donc ceci :

    CustomerService.java
    Sélectionnez
    1.
    2.
    3.
    4.
    5.
    6.
    package RestFull_Webservice_Karaf.TestRestServiceKaraf ;
     
    public interface CustomerService 
    {
    public String echo(String message);
    }
    

    Le fichier CustomerServiceImpl contient ceci :

    CustomerServiceImpl.java
    Sélectionnez
    1.
    2.
    3.
    4.
    5.
    6.
    7.
    8.
    9.
    package RestFull_Webservice_Karaf.TestRestServiceKaraf ;
    
    public class CustomerServiceImpl implements CustomerService 
    {
    public String echo(String message) 
    {
        return "Echo processed: " + message;
    }
    }
    
  7. Nous allons créer une classe CustomerBean en cliquant droit sur le package « RestFull_Webservice_Karaf.TestRestServiceKaraf » → « New » → « Class »

    Image non disponible
  8. Complétez la classe de cette manière :

    CustomerBean.java
    Sélectionnez
    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.
    package RestFull_Webservice_Karaf.TestRestServiceKaraf;
     
    import javax.xml.bind.annotation.XmlRootElement;
    
    /**
    * La classe CustomerBean est un objet JAVA contenant des méthodes get et set
    * <p/>
    * En ajoutant l'annotation @XmlRootElement, nous offrons la possibilité à JAXB de transformer cet objet en document XML et inversement.
    * <p/>
    * La représentation XML d'un customer ressemblera à ceci :
    * <Customer>
    * <id>123</id>
    * <name>Olivier</name>
    * </Customer> 
    */
    @XmlRootElement(name = "Customer")
    public class CustomerBean 
    {
    private long id;
    private String name;
    
    public long getId() 
    {
           return id;
    }
    
    public void setId(long id) 
    {
           this.id = id;
    }
    
    public String getName() 
    {
           return name;
    }
    
    public void setName(String name) 
    {
          this.name = name;
    }
    }
    
  9. De la même manière, ajoutez les classes OrderBean, Product et Products.

  10. Dans le fichier  pom.xml, ajoutez les lignes suivantes entre la balise fermante </description> et la balise ouvrante <build> afin d'ajouter les bibliothèques nécessaires au webservice en tant que dépendances Maven :

    pom.xml
    Sélectionnez
    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.
    <properties>
    <cxf.version>3.1.3</cxf.version>
    <osgi.version>6.0.0</osgi.version>
    <project.build.outputEncoding>UTF-8</project.build.outputEncoding>
    </properties>
    
    <dependencies>
    <dependency>
        <groupId>org.osgi</groupId>
        <artifactId>org.osgi.core</artifactId>
        <version>${osgi.version}</version>
        <scope>provided</scope>
    </dependency>
    
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-frontend-jaxrs</artifactId>
        <version>${cxf.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>${cxf.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>${cxf.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <version>${cxf.version}</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    

    Le contenu de la balise <osgi.version> dépendra de la version de Karaf utilisée. Les matrices de compatibilité sont disponibles ici :

    Pour Karaf 4.0.X :

    http://karaf.apache.org/index/documentation/karaf-dependencies/karaf-deps-4.0.x.html 

    Pour Karaf 3.0.X :

    http://karaf.apache.org/index/documentation/karaf-dependencies/karaf-deps-3.0.x.html

    Pour Karaf 2.4.X :

    http://karaf.apache.org/index/documentation/karaf-dependencies/karaf-deps-2.4.x.html

    Pour Karaf 2.3.X :

    http://karaf.apache.org/index/documentation/karaf-dependencies/karaf-deps-2.3.x.html

    Il suffit, dans le tableau proposé dans chacun des liens ci-dessus, de regarder la ligne « OSGI ».

    Dès lors, Karaf utilisera le repository Maven pour récupérer les bibliothèques nécessaires à notre RESTful web service.

  11. Dans le fichier pom.xml, supprimez la ligne :

    pom.xml
    Sélectionnez
    1.
    <Export-Package>RestFull_Webservice_Karaf.TestRestServiceKaraf *;version=${project.version}</Export-Package>
    

    La balise « Export-Package » permet d'indiquer les packages qui seront exportés afin que d'autres Web Service puissent utiliser les interfaces et les classes de ce package lors de leur exécution. Dans notre cas, aucun Web Service n'aura à appeller de package, la balise « Export-Package » n'est donc pas nécessaire.

  12. Configurez le fichier src/main/resources/OSGI-INF/blueprint/my-service.xml  de la manière suivante :

    my-service.xml
    Sélectionnez
    1.
    2.
    3.
    4.
    5.
    6.
    7.
    <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0" xmlns:jaxws="http://cxf.apache.org/blueprint/jaxws" xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs" xmlns:cxf="http://cxf.apache.org/blueprint/core" xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd http://cxf.apache.org/blueprint/jaxws http://cxf.apache.org/schemas/blueprint/jaxws.xsd http://cxf.apache.org/blueprint/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd  http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd">
        <jaxrs:server address="/olivier" id="someRestService">
        <jaxrs:serviceBeans>
            <ref component-id="CustomerServiceImpl"/>
           </jaxrs:serviceBeans>
         </jaxrs:server>
         <bean id="CustomerServiceImpl" class="RestFull_Webservice_Karaf.TestRestServiceKaraf.CustomerServiceImpl" /> </blueprint>
    

    Ce fichier permet d'enregistrer le service dans le registre des services et d'indiquer que son implémentation est CustomerServiceImpl. On remarque au passage qu'on y indique notre endpoint (« olivier » ici).

  13. Modifiez le fichier CustomerService.java pour y définir la classe CustomerService comme suit :

    CustomerService.java
    Sélectionnez
    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.
    85.
    86.
    87.
    88.
    89.
    90.
    91.
    92.
    93.
    94.
    95.
    96.
    97.
    98.
    99.
    100.
    101.
    102.
    103.
    104.
    105.
    106.
    107.
    108.
    109.
    110.
    111.
    112.
    113.
    114.
    115.
    116.
    117.
    package RestFull_Webservice_Karaf.TestRestServiceKaraf;
    
    import javax.ws.rs.Consumes;
    import javax.ws.rs.DELETE;
    import javax.ws.rs.GET;
    import javax.ws.rs.POST;
    import javax.ws.rs.PUT;
    import javax.ws.rs.Path;
    import javax.ws.rs.PathParam;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.Response;
    public interface CustomerService 
    {
        /**
         * Cette méthode est mappée à une requête HTTP GET : "http://localhost:8181/cxf/olivier/customers/{id}". La valeur
         * de {id} sera passée en paramètre à la méthode par utilisation de l'annotation @PathParam.
         * <p/>
         * La méthode retournera un objet de la classe CustomerBean par création d'une réponse HTTP. Cet objet sera transformé en XML par JAXB.
         * <p/>
         * Par exemple, l'appel de l'URL "http://localhost:8181/cxf/olivier/customers/123" provoquera l'affichage du customer 123 au format XML.
         */
         @GET
         @Path("/customers/{id}/")
         @Produces("application/xml")
         public CustomerBean getCustomer(@PathParam("id") String id);
    
       /**
        * Cette méthode est mappée à une requête HTTP PUT. On peut ainsi envoyer la représentation XML d'un objet customerBean.
         * La représentation XML sera obtenue par transformation d'un CustomerBean par JAXB.
       * <p/>
         * Cette méthode met à jour un objet CustomerBean dans notre map locale puis utilise la classe Response pour construire 
       * une réponse HP appropriée : soit OK si la mise à jour a été effectuée avec succès (Traduction du statut HTTP 200/OK) 
       * ou NON MODIFIE si la mise à jour de l'objet CustomerBean a échoué (Traduction du statut HTTP 304/Not Modified).  
       * <p/>
       * À NOTER : cette méthode utilise la même valeur de @path que la méthode suivante. La méthode HTTP utilisée déterminera 
       * quelle sera la méthode à invoquer
       * 
       */
       @PUT
       @Path("/customers/")
       @Consumes({"application/xml", "application/json" })
       public Response updateCustomer(CustomerBean customer);
    
    
    
      /**
       * Utilisation de la requête HTTP POST permettant d'ajouter un nouveau customer au système en uploadant la représentation XML 
       * d'un objet CustomerBean.
       * Cette opération sera mappée à la méthode ci-dessous et la représentation XML sera transformée en un objet CustomerBean.
       * <p/>
       * Après que cette méthode aura ajouté le client dans la map local, elle utilisera la classe Response pour construire la réponse HTTP 
       * en retournant à la fois l'objet CustomerBean inséré et le statut HTTP 200/OK. Ceci permet de récupérer l'ID du nouvel objet CustomerBean. 
       *<p/>
       * À NOTER : cette méthode utilise la même valeur de @path que la méthode précédente. La méthode HTTP utilisée déterminera 
        * quelle sera la méthode à invoquer
       */
       @POST
       @Path("/customers/")
       @Consumes({"application/xml", "application/json" })
       public Response addCustomer(CustomerBean customer);
    
    
     
       /**
        * Cette méthode est mappée à une requête HTTP DELETE du type : "http://localhost:8181/cxf/olivier/customers/{id}".
       * La valeur pour {id} sera passée en tant que paramètre en utilisant l'annotation @PathParam.
       * <p/>
       * Cette méthode utilise la classe Response pour créer une réponse HTTP : soit le statut HTTP 200/OK si l'objet CustomerBean 
       * a été correctement supprimé de la map locale, soit le statut HTTP 304/Not Modified si la suppression a échoué.
       */
       @DELETE
       @Path("/customers/{id}/")
       public Response deleteCustomer(@PathParam("id") String id);
    
    
      /**
        * Cette méthode est mappée à une requête HTTP GET du type : "http://localhost:8181/cxf/olivier/orders/{id}".
       * La valeur pour {id} sera passée en tant que paramètre en utilisant l'annotation @PathParam.
       * <p/>
       * La méthode retournera un objet de la classe Product par création d'une réponse HTTP. Cet objet sera transformé en XML par JAXB.
        * <p/>
       * Par exemple, l'appel de l'URL "http://localhost:8181/cxf/olivier/orders/223" provoquera l'affichage du customer 123 au format XML.
       */
       @GET
       @Path("/orders/{orderId}")
        @Produces("application/xml")
       public OrderBean getOrder(@PathParam("orderId") String orderId);
      
    
      /**
       * Cette méthode est mappée à une requête HTTP GET du type : "http://localhost:8181/cxf/olivier/orders/{id}/products/{productId}".
       * La valeur pour {id} et {productId} sera passée en tant que paramètre en utilisant l'annotation @PathParam.
       * <p/>
       * La méthode retournera un objet de la classe Product par création d'une réponse HTTP. Cet objet sera transformé en XML par JAXB.
       * <p/>
       * Par exemple, l'appel de l'URL "http://localhost:8181/cxf/olivier/orders/223/products/323/" provoquera l'affichage du customer 123 au format XML.
       */
       @GET
       @Path("/orders/{orderId}/products/{productId}")
        @Produces("application/xml")
       public Product getProduct(@PathParam("orderId") String orderId,@PathParam("productId") int productId);
    
     
      /**
       * Cette méthode est mappée à une requête HTTP GET du type : "http://localhost:8181/cxf/olivier/orders/{id}/products".
       * La valeur pour {id} sera passée en tant que paramètre en utilisant l'annotation @PathParam.
       * <p/>
       * La méthode retournera un objet de la classe Product par création d'une réponse HTTP. Cet objet sera transformé en XML par JAXB.
       * <p/>
       * Par exemple, l'appel de l'URL "http://localhost:8181/cxf/olivier/orders/223/products/323/" provoquera l'affichage du customer 123 au format XML.
       */
       @GET
       @Path("/orders/{orderId}/products")
         @Produces("application/xml")
       public Products getProducts(@PathParam("orderId") String orderId);
      
    }
    
  14. Modifiez le fichier CustomerServiceImpl.java pour y définir la classe CustomerServiceImpl comme suit :

    CustomerServiceImpl.java
    Sélectionnez
    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.
    85.
    86.
    87.
    88.
    89.
    90.
    91.
    92.
    93.
    94.
    95.
    96.
    97.
    98.
    99.
    100.
    101.
    102.
    103.
    104.
    105.
    106.
    107.
    108.
    109.
    110.
    111.
    112.
    113.
    114.
    115.
    116.
    117.
    118.
    119.
    120.
    121.
    122.
    123.
    124.
    125.
    126.
    127.
    128.
    129.
    130.
    131.
    132.
    133.
    134.
    package RestFull_Webservice_Karaf.TestRestServiceKaraf ;
    
    import java.util.HashMap;
    import java.util.Map;
    import javax.ws.rs.core.Response;
    import javax.ws.rs.PathParam;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    public class CustomerServiceImpl implements CustomerService 
    {
         private static final Logger LOG = LoggerFactory.getLogger(CustomerService.class);
    
         long currentId = 123;
         Map<Long, CustomerBean> customers = new HashMap<Long, CustomerBean>();
         Map<Long, OrderBean> orders = new HashMap<Long, OrderBean>();
    
         public CustomerServiceImpl() 
         {
            init();
            }
    
    
      /**
       * Cette méthode est utilisée par le constructeur pour insérer un objet CustomerBean et un objet OrderBean dans la map locale pour tester.
       */
      final void init() 
      {
         LOG.info("Appel de la méthode init de CustomerServiceImpl");
         CustomerBean c = new CustomerBean();
         c.setName("Olivier");
         c.setId(123);
         customers.put(c.getId(), c);
    
         OrderBean o = new OrderBean();
         o.setDescription("order 223");
         o.setId(223);
         orders.put(o.getId(), o);
      }
    
    
    
      //code retour = 500: ID invalid
      //code retour = 204: customer non trouve 
      public CustomerBean getCustomer(String id)
      {
         LOG.info("Appel de getCustomer avec l'identifiant: {}", id);
         long idNumber = Long.parseLong(id);
         CustomerBean c = customers.get(idNumber);
         return c;
       }
    
     
       public Response updateCustomer(CustomerBean customer)
       {
         LOG.info("Mise à jour d'un client dont le nom est : {}", customer.getName());
         CustomerBean c = customers.get(customer.getId());
         Response r;
         if (c != null) 
         {
            customers.put(customer.getId(), customer);
            r = Response.ok().build();
         } 
         else 
         {
             r = Response.notModified().build();
         }
    
         return r;
       }
    
    
       public Response addCustomer(CustomerBean customer)
       {
         LOG.info("Ajout d'un client dont le nom est : {}", customer.getName());
         customer.setId(++currentId);
    
         customers.put(customer.getId(), customer);
         return Response.ok().type("application/xml").entity(customer).build();
       }
    
    
       public Response deleteCustomer(String id)
       {
         LOG.info("Suppression d'un client dont l'identifiant est : {}", id);
         long idNumber = Long.parseLong(id);
         CustomerBean c = customers.get(idNumber);
    
         Response r;
         if (c != null) 
         {
             r = Response.ok().build();
             customers.remove(idNumber);
         } 
         else 
         {
             r = Response.notModified().build();
         }
    
         return r;
       }
    
    
       public OrderBean getOrder(String orderId)
       {
         LOG.info("Récupération de la commande d'identifiant : {}", orderId);
         long idNumber = Long.parseLong(orderId);
         OrderBean c = orders.get(idNumber);
         return c;
       }
    
    
       public Product getProduct(String orderId, int productId)
       {
         LOG.info("Récupération de la commande: {}", orderId);
         long idNumber = Long.parseLong(orderId);
          OrderBean c = orders.get(idNumber);
         //return c;
    
         LOG.info("Récupération du produit d'identifiant : " + productId);
         Product p = c.getProduct(productId);
         return p;
       }
    
       public Products getProducts(String orderId)
       {
         LOG.info("Récupération des produits de la commande : {}", orderId);
         long idNumber = Long.parseLong(orderId);
         OrderBean c = orders.get(idNumber);
         //return c;
    
         Products p = c.getProducts();
         return p;
       }
    }
    
  15. Modifiez le fichier OrderBean.java pour y définir la classe OrderBean comme suit :

    OrderBean.java
    Sélectionnez
    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.
    85.
    86.
    87.
    88.
    89.
    90.
    91.
    92.
    package RestFull_Webservice_Karaf.TestRestServiceKaraf;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.ArrayList;
    
    import javax.xml.bind.annotation.XmlRootElement;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
    * La classe OrderBean est un objet JAVA contenant des méthodes get et set et est aussi utilisée pour les commandes retournées par  
    * la classe CustomerServiceImpl.
    * <p/>
    * En ajoutant l'annotation @XmlRootElement, nous offrons la possibilité à JAXB de transformer cet objet en document XML et inversement.
    * <p/>
    * La représentation XML pour un OrderBean est la suivante :
    * <Order>
    * <id>223</id>
    * <description>Order 223</description>
    * </Order>
    */
    
    @XmlRootElement(name = "Order")
    public class OrderBean 
    {
    private static final Logger LOG = LoggerFactory.getLogger(CustomerService.class);
     
    private long id;
    private String description;
    //private Map<Long, Product> products = new HashMap<Long, Product>();
    private Products products = new Products();
    
    public OrderBean() 
    {
       init();
    }
    
    final void init() 
    {
       products.setProducts(new ArrayList<Product>());
       Product p1 = new Product();
       p1.setId(323);
        p1.setDescription("product 323");
      
       Product p2 = new Product();
       p2.setId(324);
       p2.setDescription("product 324");
          
       products.getProducts().add(p1);
       products.getProducts().add(p2);
    }
    
    public long getId() 
    {
       return id;
    }
    
    public void setId(long id) 
    {
       this.id = id;
    }
    
    public String getDescription() 
    {
       return description;
    }
    
    public void setDescription(String d) 
    {
       this.description = d;
    }
    
    public Product getProduct(int productId)
    {
       Product prod = null;
        for(Product p : products.getProducts())
       {
          if(p.getId()==productId)
          {
             prod = p;
          }
       }
       return prod;
    }
    
    public Products getProducts()
    {
        return products;
    }
    }
    
  16. Modifiez le fichier Product.java pour y définir la classe Product comme suit :

    Product.java
    Sélectionnez
    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.
    package RestFull_Webservice_Karaf.TestRestServiceKaraf;
    
    import javax.xml.bind.annotation.XmlRootElement;
    
    /**
    * La classe Product est un objet JAVA contenant des méthodes get et set
    * <p/>
    * En ajoutant l'annotation @XmlRootElement, nous offrons la possibilité à JAXB de transformer cet objet en document XML et inversement.
    * <p/>
    * La représentation XML d'un Product ressemblera à ceci :
    * 
    * <Product>
    * <id>10010</id>
    * <description>produit 1</description>
    * </Product>
    */
    @XmlRootElement(name = "Product")
    public class Product 
    {
    private long id;
    private String description;
    
    public long getId() 
    {
       return id;
    }
    
    public void setId(long id) 
    {
       this.id = id;
    }
    
    public String getDescription() 
    {
       return description;
    }
    
    public void setDescription(String d) 
    {
       this.description = d;
    }
    }
    
  17. Modifiez le fichier Products.java pour y définir la classe Products comme suit :
Products.java
Sélectionnez
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.
package RestFull_Webservice_Karaf.TestRestServiceKaraf;

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import java.util.List;

/**
* La classe Product est un objet JAVA contenant une liste de produits.
* <p/>
* En ajoutant l'annotation @XmlRootElement, nous offrons la possibilité à JAXB de transformer cet objet en document XML et inversement.
*
* <Products>
*     <Product>
*         <id>10010</id>
*         <description>Produit 1</description>
*     </Product>
*    <Product>
*         <id>10011</id>
*         <description>Produit 2</description>
*    </Product>
* <Products>
*/

@XmlRootElement(name = "Products")
@XmlAccessorType (XmlAccessType.FIELD)
public class Products 
{
     @XmlElement(name = "Product")
     private List<Product> productsList = null;
  
     public List<Product> getProducts() 
     {
         return productsList;
     }
 
     public void setProducts(List<Product> productsList)
     {
        this.productsList = productsList;
     }
}

VII. Compilation et Build

  1. Cliquez droit sur le projet → Run as →Maven build

    Image non disponible
  2. Dans le champ « Goals », écrivez « clean install », puis appuyez sur le bouton run

    Image non disponible
  3. Le message suivant apparaît alors :
Image non disponible

On peut y lire dans quel répertoire récupérer l'archive jar.

Il s'agit du répertoire que vous configurez dans Eclipse via Windows → Preferences → Maven →User Settings

Image non disponible

VIII. Installation et configuration de karaf

  1. Téléchargez et installez Karaf 4.0.2 sur le site http://karaf.apache.org/index/community/download.html
  2. Exécutez le fichier « karaf.bat » qui se situe dans le répertoire « bin ».
  3. Installez éventuellement la console d'administration via la commande :
    feature:install webconsole
  4. À l'issue de cette installation, on peut accéder à la console d'administration de karaf via l'UUniform Resource LocatorRL : http://localhost:8181/system/console/
    Par défaut, l'utilisateur est karaf et le mot de passe est karaf.
  5. Ajoutez le repository cxf afin que Karaf puisse installer les caractéristiques propres à cxf. Pour cela, tapez la commande suivante dans l'invite de commande :
    feature:repo-add cxf 3.0.6
  6. Tapez la commande suivante afin de vérifier que les caractéristiques cxf sont prêtes à être installées :
    feature:repo-list
    Une ligne « cxf-3.0.6 » doit alors apparaître.
  7. Si la ligne cxf-3.0.6 apparaît, l'installation peut être faite via la commande :
    feature:install cxf
  8. Vérifiez l'installation via la commande suivante :
    feature:list | grep cxf

    Image non disponible
  9. Déposez le fichier jar créé plus haut dans le répertoire « deploy » de Karaf puis re-démarrez Karaf.

  10. On peut désormais voir si notre OSGI bundle a été installé avec la commande :
    Bundle:list

    Image non disponible

    Sur la capture d'écran ci-dessus, on peut voir la ligne correspondant à notre bundle « TestRestServiceKara Blueprint Bundle ». Ce libellé peut-être configuré dans le fichier pom.xml avant de construire l'archive Jar dans Eclipse. Il s'agit alors de modifier le contenu des balises :

    xml

    <name>TestRestServiceKaraf Blueprint Bundle</name>
    <description>TestRestServiceKaraf OSGi blueprint bundle project.</description>

  11. Via la commande :
    cxf:list-endpoints
    on peut voir les endpoints cxf qui ont été installés. On peut y voir le nôtre :
Image non disponible

IX. Conclusion

Comme nous venons de le voir, le développement de RESTful web service pour Karaf est très rapide et très simple sous Eclipse, notamment avec l'utilisation de MAVEN et de l'archetype « karaf-blueprint ».

Cette méthode n'a rien à envier à Talend ESB.

Le code source de l'exemple dont il est question dans ce tutoriel est disponible à l'adresse suivante : olivier-rozier.developpez.com/tutoriels/rest/restful-webservice-karaf-eclipse/fichiers/TestRestServiceKaraf.zip

Nous venons d'étudier les bases de la création d'un RESTful web service pour Karaf .

Il serait intéressant désormais de connaître la manière de développer un RESTful web service découpé en couches applicatives et la manière d'accéder à une base de données en utilisant les Datasource et Datasource factory de Karaf. C'est ce que nous étudierons dans le tutoriel « Tutoriel pour développer et déployer un service Web RESTFUL OSGI multibundle sous Eclipse et Karaf ».

Je tiens à remercier Mickaël Baron pour la relecture technique de cet article ainsi que Claude Leloup pour la relecture orthographique.

Index

- A - Eclipse Mars (1) - K - PUT (1), (2)
archetype (1) endpoint (1) Karaf (1), (2), (3), (4), (5), (6), (7), (8) - R -
archetype MAVEN (1), (2) - G - Karaf . (1) REST (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)
- B - GET (1), (2) Karaf 4.0.2 (1) RESTful web service (1), (2), (3), (4)
Blueprint (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12), (13) - H - - M - - U -
- C - HTTP (1), (2), (3) MAVEN (1), (2), (3) URL (1), (2), (3)
CXF (1) - J - - O - - X -
- D - JAVA (1) omman (1) XML (1), (2), (3), (4), (5), (6), (7)
DELETE (1), (2) JAX-RS (1), (2) OSGI (1), (2), (3)
- E - JAX-WS (1) - P -
Eclipse (1), (2), (3), (4), (5), (6), (7) JSON (1), (2), (3), (4) POST (1), (2)

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2015 Olivier ROZIER. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.