Retour d’expérience sur les pipelines JENKINS

Depuis quelques mois, je travaille sur la migration des jobs JENKINS vers des pipelines JENKINS . Les pipelines sont une nouveauté fournie par JENKINS 2. Ça permet de décrire le cycle de vie d’un build par un DSL GROOVY

Exemple :

#!/usr/bin/groovy
@Library('malibrairie')_

node {
echo 'Demarrage du Build'

final MAVEN = "MAVEN-3.2"
final JDK = "JDK8"

try {
/* Extraction GIT/SVN + Initialisation des proprietes */
stage('Clean & Init') {
scm checkout
}
stage('Build'){
withEnv(["PATH+MAVEN=${tool MAVEN}/bin", "PATH+JAVA=${tool JDK}/bin"]) {

sh "mvn -X clean deploy -Pjdk6 -Pdev -DenvClassifier=dev -Dmaven.test.skip=true

}
}
stage('Quality') {
// lancement sonar

}

} catch (exception) {
currentBuild.result = 'FAILURE'
throw exception
} finally {
//
}
}

 

Bon je ne vous ferai pas un cours sur les pipelines, il y a déjà plusieurs sites qui font ça mieux que moi . Je vais me concentrer sur mon retour d’expérience

Les sharedlib

Ca c’est la killing feature! On peut centraliser les comportements communs à tous les builds et fournir aux projets dans leurs fichiers Jenkinsfile toute une librairie de composants. Celle-ci permet de réellement factoriser le développement des fonctionnalités de l’usine logicielle. En plus, si on couple tout ça à un repo GIT, le cycle de vie est tout trouvé: On développe sur une branche, on peut également la tester dans JENKINS et une fois OK, on publie le tout dans la branche master. Une fois publié, l’ensemble des jobs reçoit la mise à jour. Quand vous avez plus de 50 jobs à administrer, ça représente un gain de temps considérable.

Personnellement j’ai choisi de tout centraliser le comportement dans la sharedlib. De ce fait, le pipeline configuré dans chaque projet à cette forme :

#!/usr/bin/groovy

mavenNode{
  mavenJee{
  deployment=false
  }
} 

 

Exemple d’invocation d’une librairie

#!/usr/bin/groovy
@Library('malibrairie')_

 

Exemple d’invocation d’une librairie sur une branche

#!/usr/bin/groovy
@Library('malibrairie@mabranche')_

Les plugins liés à GITHUB

Sur le papier, c’est génial. On a le plugin GITHUB Organization Plugin qui permet de mapper les repo GITHUB sur une instance JENKINS.

Cependant, en entreprise, c’est difficilement utilisable ( sauf si votre entreprise opte pour une appliance ), surtout si vous avez un proxy. En effet, le plugin GITHUB API ne supporte pas les proxy. Bref, je n’ai pas pu pleinement exploiter toutes les fonctionnalités d’un couplage GITHUB/JENKIINS.

La documentation

Même si l’équipe a refait toute la doc, je ne la trouve pas top. J’ai eu du mal à m’y faire au début. J’ai eu plus d’informations en naviguant sur quelques repo GITHUB que sur la documentation.Pour la référence de tous les steps, ça va, mais je ne la trouve pas didactique.

En résumé

Même si il y a quelques déconvenues, les pipelines sont une évolution majeure de JENKINS. Ca m’a permis de perdre du temps dans les écrans d’administration et de factoriser les différents build grâce à du code GROOVY.  Si vous avez encore des JOBS JENKINS « legacy », n’hésitez plus !

Pour aller plus loin

Si vous voulez plus d’exemples et de détails je vous conseille ces liens :

Après 1 mois de JHIPSTER

Dans un lointain article, j’ai commencé à bidouiller avec JHIPSTER. Pour répondre à un besoin professionnel « one shot », j’ai décidé d’ utiliser ce framework car je n’avais pas pas beaucoup de temps à m’y consacrer.
Voici un rapide retour d’expérience d’un mois ( en pointillé ) d’utilisation.

Cas d’utilisation

Le cas d’utilisation se prêtait bien à JHIPSTER:

  • CRUD
  • Authentification via les réseaux sociaux
  • Application responsive permettant d’être manipulée via pc, tablette ou téléphone
  • Interface d’administration

Ce que JHIPSTER m’a permit de réaliser très simplement

  • L’interface d’administration était déjà prête pour moi. Je n’ai eu qu’à customiser certains comportements .
  • La création du front et back pour mes entités . Ici JHIPSTER est très fort. Ca fonctionne très bien. A tel point que pour une modification, j’en suis venu à supprimer et refaire ma configuration.
  • La sécurité : tout est mis en place ( JWT, Authentification via réseaux sociaux). Des directives ANGULAR sont également disponibles pour gérer les habilitations sur certaines parties de l’interface graphique (ex. has-authority).
  • L’intégration de docker. Tout est déjà crée pour vous 🙂
  • La mécanique JAVASCRIPT. Ce n’est pas ce que je préfère. JHIPSTER m’ a permis d’avoir un cadre de développement qui corresponde à mes besoins.
  • La création des pipelines JENKINS ou GITLAB

La ou j’ai galéré

Comme j’indiquai dans mon précédent post, dès qu’on sort du cadre, on galère un peu… Je n’ai pas échappé à la règle.

AngularJS vs html5

Bien que cela soit documenté. J’ai un peu galéré à activer le mode html5. J’ai eu quelques effets de bord sur les liens.

Permalien

Pour ce point, je pense que le soucis est plus dû à mon inexpérience de développeur WEB ( je suis plus back que front …).J’ai du implémenter une URL accessible directement sans passer par la page d’accueil (accès). J’ai opté pour une URL publique. La ça a été le début des problèmes. La CSS ne se charge pas tout le temps.
Bon pour ce cas d’utilisation, je ne me suis pas trop pris la tête. Je pense qu’une solution plus viable serait déjà de passer par Angular2/4 et de mettre des redirections dans le frontal NGINX

En conclusion

Le retour est positif. Pour une application « one-shot » c’est parfait. Je pense que pour une prochaine application je partirai sur du Angular et non du AngularJS. Pour une application métier plus poussée, je partirai sur un seed maison pour maitriser et avoir la main sur l’évolution de toutes les couches. Une autre chose qui m’a un peu étonné était le ratio entre développement BACK et FRONT. J’ai passé près de 70% dans le développement ANGULARJS. Spring et la génération JHIPSTER embarque déjà pas mal de fonctionnalités.

Devoxx 2017

Me voila au bout de trois jours de conférences suivies au ( ou à je ne capte plus grand chose à cette heure de la journée ) DEVOXX.


DEVOXX, pour celles et ceux qui ne connaissent pas est LA conférence pour les développeurs.
Initialement tournée autour de JAVA et JAVAEE, elle s’est tournée au fil des années vers les autres technologies qui tournent autour de JAVA ( ANGULAR, BIG DATA,…).

A l’instar des années précédentes, j’ai trouvé les conférences de ( grande) qualité. J’ai appris pas mal de choses et certaines conférences m’ont permis de « mettre l’église au milleu du village » sur pas mal de sujets .

Vous trouverez sur cette page la liste des conférences, hands on et autres ateliers de ce millésime. Personnellement, j’ai assisté à pas mal de conférences sur le bigdata ( hadoop, kafka, spark,…). J’ai également été étonné que ni google, ni oracle étaient présents cette année. Doit-on y voir un signe ?

Les conférences seront diffusées gratuitement sur YOUTUBE.

Sur ce, je m’en vais prendre mon train pour retourner dans ma campagne et récupérer de ces trois jours .

 

Installation de GNU/LINUX sur un lenovo thinkcentre m700

J’ai décidé de changer de PC. J’ai opté pour un Lenovo thinkcentre m700 afin de gagner pas mal de place et perdre quelques décibels à l’utilisation 🙂

Pour info, voici les caractéristiques techniques du modèle acheté

 

  • Modèle du processeur : Intel Core i5 6400T
  • Fréquence : 2.2 Ghz (2,8 Ghz avec TurboBoost)
  • Capacité mémoire installée : 8192 Mo
  • Marque de la carte graphique : Intel
  • Puce graphique : Intel® HD Graphics 530

 

Pour écouter la musique, j’ai également fait l’acquisition d’un DAC USB NUPRIME UDSD.

 

Après quelques backups fait sur windows 10 ( histoire de gérer le support plus tard), j’ai décidé d’installer GNU/LINUX.

J’ai tout d’abord cherché la compatibilité des différents matériaux. Pour le PC, je n’ai trouvé que l’info sur la compatibilité UBUNTU. Pour le nuprime, j’ai seulement trouvé la compatibilité avec le NAS SYNOLOGY sur le support NUPRIME. Vu que ce dernier est basé sur GNU/LINUX, j’étais plutôt confiant 🙂

Mon premier choix s’est tourné sur DEBIAN (8.7) …. et là j’ai galéré 🙁

L’installation s’est bien déroulé, mais

  • Pas de son (interne & DAC ) Les modules snd-hda-intel et snd-usb-audio étaient un peu bancales
  • Le système était un peu instable : A ce que j’ai lu sur quelques sites, la compatibilité avec l’architecture SKYLAKE et les processeurs Intel 6ème génération n’est pas encore optimale
  • etc.

Après quelques tentatives de backport, passage en testing et voodoo, j’ai décidé d’installer UBUNTU LINUX 16.04 LTS.

Et oui je suis revenu sur UBUNTU :). Là, tout fonctionne parfaitement .

  • La carte son (interne & via displayport)
  • Mon DAC fonctionne parfaitement
  • La vidéo
  • Wifi/Bluetooth/…

Bref tout va bien 🙂

Seul « petit » problème, j’ai essayé d’installer gnome-shell. J’ai sélectionné gdm3 au lieu de lightdm et j’ai eu un gros freeze de mon PC. Impossible de réparer ça. J’ai du réinstaller. Vu la vitesse, ce n’est pas trop grave.

J’ai décidé de rester pour l’instant sur UBUNTU avec le desktop UNITY. Peut-être que je basculerai sur la prochaine version de Debian quand elle sortira.

Je vous fait grâce de la liste des paquets que j’ai installé et de la configuration que j’applique. Il y a suffisamment de sites qui font ça mieux que moi 🙂

 

 

 

 

Création clé bootable GNU/LINUX (simplement)

J’ai décidé récemment de changer de PC. Afin de pouvoir installer Debian (what else) dessus, il me faut créer une clé USB Bootable. Et oui, le temps ou il y avait des lecteurs de CD/DVD est révolu…

J’ai regardé sur la documentation et plus largement sur Internet et je suis tombé sur ce logiciel : etcher. Il est libre et multi-plateforme.

Plus simple il n’y a pas 🙂

Vous sélectionnez l’image, le périphérique et c’est parti.

L’utilitaire fait une vérification après flash.

Quelques problèmes

Après flash, il se peut que ayez des messages au montage de la clé tels que

Après quelques tests, ça n’empêche pas la clé de booter, mais la rend inutilisable pour tout autre utilisation.

A ce que j’ai lu, c’est principalement dû à la commande dd qui fout un peu la zone…

Pour corriger ceci, il faut réinitialiser la clé avec la commande :

ou sdX est le périphérique de la clé USB.

 

 

En espérant que ça puisse servir à d’autres dans mon cas.

Découverte de JHIPSTER

Dans la série, je me réveille après les autres, me voici en train de découvrir JHIPSTER.


Pourquoi me direz-vous. En bien je souhaite réaliser un site avec des fonctionnalités assez courantes (CRUD, recherche, identification via réseaux sociaux,…) sans trop me prendre la tête. Et là, je n’ai pas encore trouvé plus simple :).

J’étais tenté de passer par PlayFramework, mais à première vue, JHIPSTER parait plus simple à mettre en œuvre.

Mais bon qu’est-ce qu’il y a sous le capot ?
Un outil de scaffolding basé sur Yeoman fournissant un front angular (1ou 2) un back basé sur spring boot, une couche de persistance pour une base de données (mongodb, cassandra ou SGBDR) et bien plus encore.

Je ne décrirai pas la procédure d’installation car elle est déjà très bien documentée.

Voici plus précisément les fonctionnalités que je teste :
Coté front

  • AngularJS
  • Bootstrap
  • JWT

Coté Back

  • Spring Boot
  • Identification avec Spring Social / Spring Security
  • Persistence avec MongoDB ( Cassandra n’est pas encore supporté pour l’identification via réseaux sociaux )
  • Utilisation de SWAGGERUI pour documenter les API

J’ai toujours été un peu réticent vis à vis des outils de ce type ( appfuse, jboss forge,..) . Mais, là je suis bluffé. Si on veut faire une application de type CRUD sans se prendre la tête à réinventer la roue pour l’identification, l’ administration des logs, la documentation, etc , JHIPSTER est, à mon avis, l’un des meilleurs choix actuellement.

Cependant, cette intégration à un coût. En effet, l’équipe a fait des choix très structurants. Ce qui est normal pour fournir une solution aussi intégrée. Il faut les accepter si on opte pour ce genre de solution. Par exemple, le monitoring des services springboot est uniquement visible par une console web alors quand dans version standard de ce FRAMEWORK, c’est visible via API REST. C’est certes pas mal quand on est tout seul à gérer l’application, mais dès que l’on veut intégrer la supervision dans une entreprise qui dispose déjà d’outils tels que NAGIOS, cela devient plus problématique.
(Supprimé suite au commentaire de J. DUBOIS)

Pour finir, je dirais que l’une des contraintes à accepter lorsqu’on utilise ce genre de FRAMEWORK est qu’il faut rester dans le cadre préétabli pour qu’il y ait une réelle productivité. Si on veut tordre le modèle on risque de perdre en efficacité et en maintenabilité. A titre personnel pour mon use case, je m’en accommode bien et ça me permet de faire plus de choses en JAVASCRIPT que je n’aurai pu faire avec une application réalisée « from scratch ».

Création d’une alerte dans ELASTICSEARCH

Après avoir crée la requête dans ELASTICSEARCH me permettant de récupérer les services ESB qui ne seraient pas dans un état normal, il ne me reste plus qu’à gérer l’alerte avec XPACK

J’ai modifié ma requête pour en faire un template.

POST /_search/template/esb-alert-search
{
  "template":{
  "size": 0,
  "query": {
    "range": {
      "JOBSTART": {
        "gte": "{{date_min}}",
        "lte": "now"
      }
    }
  },
  "aggs": {
    "services": {
      "terms": {
        "field": "DEPLOYMENT_NAME"
      },
      "aggs": {
        "success": {
          "filter": {
            "term": {
              "STATUS": "sucess"
            }
          }
        },
        "errors": {
          "filter": {
            "term": {
              "STATUS": "error"
            }
          }
        },
        "percentage": {
          "bucket_script": {
            "buckets_path": {
              "numberOfSuccess": "success>_count",
              "numberOfErrors": "errors>_count"
            },
            "script": "params.numberOfErrors /(params.numberOfErrors+params.numberOfSuccess)"
          }
        },
        "services_error_filtered": {
          "bucket_selector": {
            "buckets_path": {
              "threesold": "percentage"
            },
            "script": "params.threesold > {{threeshold}}"
          }
        }
      }
    }
  }
  }
}

Ensuite, j’ai crée l’alerte qui loggue l’alerte dans les logs d’ELASTICSEARCH et peuple un index dédié aux alertes. Bien évidemment, on peut appeler un service REST pour créer un ticket dans un BUGTRACKER par exemple.

put _xpack/watcher/watch/esb-alert
{
  "trigger": {
    "schedule": {
      "interval": "30s"
    }
  },
  "input": {
    "search": {
      "request": {
        "indices": [
          "monitor2"
        ],
        "template": {
          "stored": "esb-alert-search",
          "params": {
            "date_min": "now-1d/d",
            "threeshold": "0.5"
          }
        }
      }
    }
  },
  "condition": {
    "script": {
      "inline": "return ctx.payload.aggregations.services.buckets.size() > 0"
    }
  },
  "actions": {
    "log": {
      "logging": {
        "level": "warn",
        "text": "Errors have occured in the logs"
      }
    }
  }
}

 

Maintenant les alertes sont disponibles dans mon index et visibles par exemple via un rapport KIBANA 🙂

Recherche des erreurs d’un ESB dans ELASTICSEARCH

,Depuis quelques temps, on a extrait les différents appels transitant dans un ESB (TIBCO BW dans mon cas) pour les déverser dans ELASTICSEARCH. On peut même utiliser la plateforme CONFLUENT pour faire du Change Data Capture pour transférer les données via KAFKA.

Cette solution permet de déterminer quelques statistiques intéressantes telles que le nombre d’appels, le nombre d’erreurs par service,…

Au delà des beaux graphiques fournis par KIBANA, je suis en train de me plonger dans la gestion des alertes. En effet, dans l’addon payant d’ELASTICSEARCH (XPACK), il y a un plugin assez intéressant : WATCHER.

Ce dernier permet, grâce à la percolation de lancer des alertes via API REST par exemple. Celles-ci sont déclenchées de manière périodique via un système analogue au CRON.

Dans cet article, je décrirai la requête et le mapping de données qui me permettent de stocker les données et de faire la recherche en question. Je décrirai dans un futur article, la création de l’alerte

 

Mapping

put /monitoring
{
    "settings" : {
        "number_of_shards" : 1
    },
    "mappings": {
      "monitoring": {
        "properties": {
          "DEPLOYMENT_NAME": {
            "type": "keyword"
          },
          "DURATION_MS": {
            "type": "long"
          },
          "JOBEND": {
            "type": "date"
          },
          "JOBSTART": {
            "type": "date"
          },
          "LOGID": {
            "type": "text"
          },
          "STATUS": {
            "type": "keyword"
          }
        }
      }
    }
}

Requête

Mon besoin est d’identifier les services qui ont un fort taux d’erreur et de lancer une erreur le cas échéant. Par exemple, si un service a 30% d’erreur pendant un laps de temps de 30mn, on pourra appeler via une API REST un service de création d’anomalie (ex. JIRA).

Voici la requête que j’ai crée.Celle-ci utilise le mécanisme des agrégations pour déterminer pour chaque service le pourcentage d’erreur.

POST /monitoring/_search
{
  "size": 0,
  "query": {
    "range": {
      "JOBSTART": {
        "gte": "now-15d/d",
        "lte": "now"
      }
    }
  },
  "aggs": {
    "services":{
      "terms":{
        "field": "DEPLOYMENT_NAME"
      },
      "aggs": {
        "success":{
          "filter":{
            "term": {
              "STATUS": "success"
            }
          }
        },
         "errors":{
          "filter":{
            "term": {
              "STATUS": "error"
            }
          }
        },
    "percentage": {
          "bucket_script": {
            "buckets_path": {
              "numberOfSuccess": "success>_count",
              "numberOfErrors": "errors>_count"
            },
            "script": "params.numberOfErrors /(params.numberOfErrors+params.numberOfSuccess)"
          }
        },
        "services_error_filtered": {
          "bucket_selector": {
            "buckets_path": {
              "threesold": "percentage"
            },
            "script": "params.threesold > 0.5"
          }
        }
      }
    }
  }
}

Conclusion

Maintenant j’ai ma requête ELASTICSEARCH. La suite dans un autre article pour la création de l’alerte

 

 

Utilisation de la plateforme CONFLUENT pour faire du CDC

Après une pause dans mon exploration de KAFKA et KAFKA CONNECT, je me suis remis à faire du CDC.

Cette fois j’ai décidé d’utiliser les possibilités natives de la plateforme CONFLUENT. A savoir le proxy REST et les plugins JDBC et ELASTICSEARCH.

J’ai donc mis en quelques coups de cuillères à pot :

  • Une extraction de données incrémentale à partir d’une base de données
  • Un chargement dans Elasticsearch

 

Création des connecteurs

Création du connecteur d’extraction

La plateforme CONFLUENT offre un ensemble d’APIS qui permettent la configuration des connecteurs.

Ex. :

Lecture d’un état de connecteur

 curl -XGET http://127.0.0.1:8083/connectors

 

Voila comment j’ai chargé la configuration :

J’ai d’abord crée un fichier JSON

{
  "name": "jdbc-sql",
  "config": {
    "connector.class": "io.confluent.connect.jdbc.JdbcSourceConnector",
    "tasks.max": 2,
    "connection.url": "jdbc:oracle:thin:URL",
    "mode": "incremental",
    "timestamp.column.name": "JOBSTART",
    "query":"select * from LOG",
    "topic.prefix": "jdbc-avro-jdbc",
    "table.types" : "VIEW"
  }
}

puis je l’ai chargé via l’API en utilisant une requête POST

Création du connecteur déversant dans Elasticsearch

Même principe avec ce fichier JSON

{
  "name": "jdbc-elk-sink",
  "config": {
    "connector.class": "io.confluent.connect.elasticsearch.ElasticsearchSinkConnector",
    "tasks.max": 2,
    "connection.url": "http://host:9200",
    "type.name": "monitor",
    "topics": "jdbc-avro-jdbc",
    "topic.key.ignore": "jdbc-avro-jdbc",
    "topic.index.map":"jdbc-avro-jdbc:monitor",
    "key.ignore": "true"
  }
}

Avec cette configuration j’ai maintenant un cluster ELASTICSEARCH qui récupère au fil de l’eau mes données provenant de la base de données.

Configurer weblogic pour se connecter à une queue TIBCO EMS

Cet article sera un peu moins rock & roll mais pourra peut-être être utile pour certains.
Je souhaite dans le contexte d’une application JEE hébergée sur weblogic consommer les messages d’une queue JMS hebergée sur TIBCO EMS.

Pre-requis

  • Il faut que la queue présente dans TIBCO EMS soit statique et non dynamique
  • Il faut que la queue EMS ait un nom JMDI
  • Il faut que les droits soient positionnés dans EMS

Dépendances

Il faut installer les JARS suivants dans le répertoire lib du domaine weblogic

  • jms.jar
  • jms-2.0.jar
  • tibcrypt.jar
  • tibemsd_sec.jar
  • tibjms.jar
  • tibjmsadmin.jar
  • tibjmsapps.jar
  • tibjmsufo.jar
  • tibrvjms.jar

Configuration weblogic

Il faut réaliser les actions suivantes :

Créer le module JMS et l’assigner sur le serveur managé

Dans ce module JMS, créer une queue distante et renseigner les informations suivantes :

Maintenant renseigner les informations suivantes :

  • Fabrique de contextes initiale JNDI: com.tibco.tibjms.naming.TibjmsInitialContextFactory
  • URL de connexion JNDI : Elle est au format tibjmsnaming://MONSERVEUR:7222
  • Identification : le mot de passe de l’utilisateur
  • Propriété JNDI : le login de l’utilisateur avec la clé java.naming.security.principal
  • Activer le ciblage par défaut

Ensuite, il faut spécifier la destination en indiquant le nom JNDI local et le nom JNDI spécifié sur EMS.

Enfin, il faut spécifier la fabrique de connexion.

sélectionner l’onglet « Fabrique de connexion » et cliquer sur « Nouveau »

Renseigner les informations suivantes :

  • Nom JNDI local : nom JNDI nécessaire au bean MDB pour envoyer les messages
  • Nom JNDI distant : nom JNDI configuré sur EMS
  • Identifiant / Mot de passe : les mêmes que précédemment

Au final vous devriez avoir ce fichier de configuration généré

<?xml version='1.0' encoding='UTF-8'?>
<weblogic-jms xmlns="http://xmlns.oracle.com/weblogic/weblogic-jms" 
			  xmlns:sec="http://xmlns.oracle.com/weblogic/security" 
			  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
			  xmlns:wls="http://xmlns.oracle.com/weblogic/security/wls" 
			  xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-jms http://xmlns.oracle.com/weblogic/weblogic-jms/1.1/weblogic-jms.xsd">
  <foreign-server name="ForeignServer-0">
    <default-targeting-enabled>true</default-targeting-enabled>
    <foreign-destination name="ForeignDestination-0">
      <local-jndi-name>jms.Queue</local-jndi-name>
      <remote-jndi-name>queue.sample</remote-jndi-name>
    </foreign-destination>
    <foreign-connection-factory name="ForeignConnectionFactory-0">
      <local-jndi-name>jms.TibcoConnectionFactory</local-jndi-name>
      <remote-jndi-name>QueueConnectionFactory</remote-jndi-name>
      <username>weblogic</username>
      <password-encrypted>{AES}vD1uLZ</password-encrypted>
    </foreign-connection-factory>
    <initial-context-factory>com.tibco.tibjms.naming.TibjmsInitialContextFactory</initial-context-factory>
    <connection-url>tibjmsnaming://MONSERVEUR:7222</connection-url>
    <jndi-properties-credential-encrypted>{AES}/8v3owbSW</jndi-properties-credential-encrypted>
    <jndi-property>
      <key>java.naming.security.principal</key>
      <value>weblogic</value>
    </jndi-property>
  </foreign-server>
</weblogic-jms>
weblogic

Consommation des messages via un EJB MDB

@MessageDriven(mappedName = "jms.Queue", activationConfig = {
        @ActivationConfigProperty(propertyName = "acknowledgeMode",
                propertyValue = "Auto-acknowledge"),
        @ActivationConfigProperty(propertyName = "destinationType",
                propertyValue = "javax.jms.Queue"),
        @ActivationConfigProperty(propertyName = "connectionFactoryJndiName", propertyValue = "jms.TibcoConnectionFactory")
})
public class SampleMDBean implements MessageListener {
    @Override
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public void onMessage(Message message) {
      //
    }
}
jms