Upload
antoine-sabot-durand
View
1.600
Download
7
Tags:
Embed Size (px)
DESCRIPTION
Slides de la conférence donnée par Alexis Hassler et Antoine Sabot-Durand à Devoxx France 2014 sur les possibilités d'extensions de Java EE. Y sont évoqués l'utilisation de CDI et de son système d'extension ainsi que de JCA à travers le développement d'un connecteur MQTT.
Citation preview
@AlexisHassler @Antoine_SD#J3E
Avec JavaEE, fais ce que tu veux…
@Antoine_SD RedHat Senior Software Developer
@AlexisHassler Sewatech Développeur, Formateur
@AlexisHassler @Antoine_SD#J3E
Antoine Sabot-Durand
•Senior Software Developer @Red Hat !
•Java & OSS :
• CDI co-spec lead
• CDI eco-system development
• Tech Lead on Agorava
!
•@antoine_sd
•@cdispec
@AlexisHassler @Antoine_SD#J3E
Alexis Hassler
•Développeur, formateur Java
•Indépendant !
!
•Co-leader du !
!
•@AlexisHassler
@AlexisHassler @Antoine_SD#J3E
Plan
CDI JCA
Java EE
Synthèse
@YourTwitterHandle#DVXFR14{session hashtag} @AlexisHassler @Antoine_SD#J3E
Java
EE
@AlexisHassler @Antoine_SD#J3E
Java
EE
App
licat
ion
Serv
er
Java EE
Java SE
Containers (Servlet, EJB, CDI)
Con
nect
ors
Transactions
Security
Messaging
Persistence
…
Outils
@AlexisHassler @Antoine_SD#J3E
Java EE
Front End
Business Logic
PersistenceJPA
EJB 3
JSF
@AlexisHassler @Antoine_SD#J3E
CDI
Java EE
JSF
EJB 3
JPA
@AlexisHassler @Antoine_SD#J3E
Java EE
JSF JAX-RS
WebSocket
@AlexisHassler @Antoine_SD#J3E
Java EE
Servlet
JSP
JSP debugging
JSTL
EL
WebSocket
JSF
ManagedBeans CDI
Beans Validation
CommonsAnnotations
JAX-RS
JSON-P
JASPIC
JACC
JAX-WS
JAXB JAXM
Web Services Metadata
Enterprise Web Services
Batch
JMS
JCA
Java Mail
EJB remote
EJB entity
JAX-RPC
JAXR
Application Deployment
Concurrency Utilities
EJB Lite JPA
DI Interceptor JTA
ManagementState
Management
@AlexisHassler @Antoine_SD#J3E
Java EE
J2EE 1.2 Servlet / JSP
EJB JMS
RMI / IIOP
J2EE 1.3 !
… !
EJB CMP JCA
J2EE 1.4 !
… !
Web Services Management Deployment
Java EE 5 !
… !
Annotations EJB 3 JPA
WS-* JSF
Java EE 6 …
JPA 2 JSF 2
JAX-RS CDI
@Inject Bean Validation
Web
Profi
le
Man
aged
Bean
s
Java EE 7 !
… !
Batch Web Socket
JSON-P @Transaction
JMS 2
Web
Profi
le
Man
aged
Bean
s
1999 10 specs
2001 13 specs
2003 20 specs
2006 23 specs
2009 28 specs
2013 30 specs
@AlexisHassler @Antoine_SD#J3E
!
!
CDI JCA
@YourTwitterHandle#DVXFR14{session hashtag} @AlexisHassler @Antoine_SD#J3E
Les b
ases
de C
DI
@AlexisHassler @Antoine_SD#J3E
•CDI c’est beaucoup de choses
• Un standard de l’IoC pour Java EE et Java SE
• Un standard pour la gestion des contexts
• Un Système de gestion d’événements
• Un liant pour la plupart des spec Java EE
• Le moteur pour faire évoluer Java EE grace aux extensions potables
• Le tout tirant partie du typage fort de Java.
Context & Dependency Injection
@AlexisHassler @Antoine_SD#J3E
Les principaux jalons de CDI
•Dates clés :
• Décembre 2009 : CDI 1.0
• Juin 2013 : CDI 1.1
• Avril 2014 : CDI 1.2
• été 2014 : début du développement sur CDI 2.0
•Toutes les infos sur : http://cdi-spec.org
•Implémentations :
• JBoss Weld (RI) : WildFly, JBoss EAP, Glassfish, Weblogic
• Apache OpenWebBeans : TomEE, Websphere
@AlexisHassler @Antoine_SD#J3E
CDI est activé par défaut dans Java EE 7
•Dans Java EE 6, il faut ajouter le fichier beans.xml au déploiement
•Le fichier est optionnel dans EE 7 mais permet d’assurer un fonctionnement compatible EE 6
beans.xml
@AlexisHassler @Antoine_SD#J3E
Bean
•En Java EE 6 et 7 tout est Managed Bean
• le managed bean est le composant de base
• il a un cycle de vie géré par le conteneur CDI
• il est injectable
• il supporte l’AOP via les intercepteur et les décorateurs
• accessible depuis des environnements non CDI
@AlexisHassler @Antoine_SD#J3E
Dependency Injection
@Inject
@AlexisHassler @Antoine_SD#J3E
public class HelloService {! public String hello() {! return "Hello World!";! }!}
Dependency Injection
@AlexisHassler @Antoine_SD#J3E
public class MyBean {!! private HelloService service;!! @Inject! public MyBean(HelloService service) {! this.service = service;! }! public void displayHello() {! display( service.hello();! }!}
Dependency Injection in constructor
@AlexisHassler @Antoine_SD#J3E
public class MyBean {!! private HelloService service;!! @Inject! public void setService(HelloService service) {! this.service = service;! }! public void displayHello() {! display( service.hello();! }!}
Dependency Injection in setter
@AlexisHassler @Antoine_SD#J3E
public class MyBean {!! @Inject HelloService service;!! public void displayHello() {! display( service.hello();! }!}
Dependency Injection in field
@AlexisHassler @Antoine_SD#J3E
public interface HelloService {! public String hello();!}!public class FrenchHelloService implements HelloService {! public String hello() {! return "Bonjour tout le monde!";! }!}!public class EnglishHelloService implements HelloService {! public String hello() {! return "Hello World!";! }!}
Qualifiers
@AlexisHassler @Antoine_SD#J3E
@Qualifier!@Retention(RUNTIME)!@Target({FIELD, TYPE, METHOD, PARAMETER}) !public @interface French {}!!@Qualifier!@Retention(RUNTIME)!@Target({FIELD, TYPE, METHOD, PARAMETER}) !public @interface English {}
Qualifiers
@AlexisHassler @Antoine_SD#J3E
@French!public class FrenchHelloService implements HelloService {! public String hello() {! return "Bonjour tout le monde!";! }!}!!@English!public class EnglishHelloService implements HelloService {! public String hello() {! return "Hello World!";! }!}
Qualifiers
@AlexisHassler @Antoine_SD#J3E
public class MyBean {! @Inject @French HelloService service;! public void displayHello() {! display( service.hello();! }!}!public class MyBean {! @Inject @English HelloService service;! public void displayHello() {! display( service.hello();! }!}
Qualifiers
@AlexisHassler @Antoine_SD#J3E
@Qualifier!@Retention(RUNTIME)!@Target({FIELD, TYPE, METHOD, PARAMETER}) !public @interface Language {!! Languages value();! ! @Nonbinding String description() default "";!! public enum Languages { ! FRENCH, ENGLISH! }!}
Qualifiers avec membres
@AlexisHassler @Antoine_SD#J3E
@Language(FRENCH)!public class FrenchHelloService implements HelloService {! public String hello() {! return "Bonjour tout le monde!";! }!}!@Language(ENGLISH)!public class EnglishHelloService implements HelloService {! public String hello() {! return "Hello World!";! }!}
Qualifiers
@AlexisHassler @Antoine_SD#J3E
public class MyBean {! @Inject @Language(ENGLISH) HelloService service;! public void displayHello() {! display( service.hello();! }!}!!public class MyBean {! @Inject @Language(FRENCH) HelloService service;! public void displayHello() {! display( service.hello();! }!}
Qualifiers
@AlexisHassler @Antoine_SD#J3E
public class MyBean {! @Inject @French ! HelloService service;!}!!@French @Console @Secured!public class FrenchHelloService implements HelloService {!!}
Qualifiers
@AlexisHassler @Antoine_SD#J3E
public class MyBean {! @Inject @French @Console! HelloService service;!}!!@French @Console @Secured!public class FrenchHelloService implements HelloService {!!}
Qualifiers
@AlexisHassler @Antoine_SD#J3E
public class MyBean {! @Inject @French @Console @Secured ! HelloService service;!}!!@French @Console @Secured!public class FrenchHelloService implements HelloService {!!}
Qualifiers
@AlexisHassler @Antoine_SD#J3E
public class MyBean {! @Inject @French @Console @Secured ! HelloService service;!}!!@French @Secured!public class FrenchHelloService implements HelloService {!!}
Qualifiers
@AlexisHassler @Antoine_SD#J3E
Qualifiers réservés
@Default!@Any!@Named
@AlexisHassler @Antoine_SD#J3E
public class MyBean {!! @Inject Instance<HelloService> service;!! public void displayHello() {! display( service.get().hello() );! }!}
Programmatic lookup
@AlexisHassler @Antoine_SD#J3E
public class MyBean {!! @Inject Instance<HelloService> service;!! public void displayHello() {! if (!service.isUnsatisfied()) {! display( service.get().hello() );! }! }!}
Programmatic lookup
@AlexisHassler @Antoine_SD#J3E
public class MyBean {!! @Inject @Any Instance<HelloService> services;!! public void displayHello() {! for (HelloService service : services) {! display( service.hello() );! }! }!}
Programmatic lookup
@AlexisHassler @Antoine_SD#J3E
public class MyBean {!! @Inject @Any Instance<HelloService> services;!! public void displayHello() {! display( ! service.select(! new AnnotationLiteral()<French> {})! .get() );! }!}
Programmatic lookup
@AlexisHassler @Antoine_SD#J3E
Programmatic lookup
•L’injection programmatique permet de sélectionner un bean au runtime en fonction de son type et de ses qualifiers
•Comme les qualifiers sont des annotations (donc non instantiables), il faut utiliser la classe AnnotationLiteral pour créer une instance de l’annotation
•De même, pour palier au phénomène de type erasure on pourra utiliser la classe TypeLiteral pour rechercher un type paramétré
@AlexisHassler @Antoine_SD#J3E
Contexts
•Gestion du cycle de vie des beans
• choix du moment de la création et de la destruction des beans
• ‘un singleton pour un contexte donné’
• Possibilité de créer des scopes personnalisés
• via les extensions
•CDI contexts fournis dans la specification:
• @Dependent (default)
•@RequestScoped!
•@SessionScoped!
•@ConversationScoped!
•@ApplicationScoped
@AlexisHassler @Antoine_SD#J3E
@SessionScoped!public class CartBean {!! public void addItem(Item item) {! ...! } !}
Contexts
@AlexisHassler @Antoine_SD#J3E
@ApplicationScoped!public class CartBean {!! public void addItem(Item item) {! ...! } !}
Contexts
FAIL !!
!
@AlexisHassler @Antoine_SD#J3E
@ConversationScoped!public class CartBean {!! public void addItem(Item item) {! ...! } !}
Contexts
@AlexisHassler @Antoine_SD#J3E
@ThreadScoped!public class CartBean {!! public void addItem(Item item) {! ...! } !}
Contexts
@AlexisHassler @Antoine_SD#J3E
@HourScoped!public class CartBean {!! public void addItem(Item item) {! ...! } !}
Contexts
@AlexisHassler @Antoine_SD#J3E
@RandomScoped!public class CartBean {!! public void addItem(Item item) {! ...! } !}
Contexts
@AlexisHassler @Antoine_SD#J3E
@Produces!public MyNonCDIClass myProducer() {!return new MyNonCdiClass();!}!...!@Inject!MyNonCDIClass bean;!
Producers
@AlexisHassler @Antoine_SD#J3E
@Produces!@RequestScoped!public FacesContext produceFacesContext() {! return FacesContext.getCurrentInstance();!}
Producers
@AlexisHassler @Antoine_SD#J3E
@Produces!public Logger produceLog(InjectionPoint injectionPoint) {! return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());!}
Producers
@AlexisHassler @Antoine_SD#J3E
@Decorator!@Priority(Interceptor.Priority.APPLICATION)!public class HelloDecorator implements HelloService {!! @Inject @Delegate HelloService service;!! public String hello() {! return service.hello() + "-decorated";! }!}
Decorators
@Inject HelloService service;
@AlexisHassler @Antoine_SD#J3E
@InterceptorBinding!@Target({METHOD, TYPE}) !@Retention(RUNTIME)!public @interface Loggable {}
Interceptors
@AlexisHassler @Antoine_SD#J3E
@Interceptor @Loggable !public class LogInterceptor {! @AroundInvoke! public Object log(InvocationContext ic) throws Exception {! System.out.println("Entering " + ic.getMethod().getName());! try {! return ic.proceed(); ! } finally {! System.out.println("Exiting " + ic.getMethod().getName());! }! } !}
Interceptors
@AlexisHassler @Antoine_SD#J3E
@Loggable!public class MyBean {!! @Inject HelloService service;!! public void displayHello() {! display( service.hello();! }!}
Interceptors
@AlexisHassler @Antoine_SD#J3E
@Inject Event<Post> evt;!!…!!evt.fire(new Post("John Doe ", "Hello", ));!!…!!public void receiveEvt(@Observes Post evt) {! System.out.println("Received : " + evt.message());!}
Events
@YourTwitterHandle#DVXFR14{session hashtag} @AlexisHassler @Antoine_SD#J3E
CDI
exte
nsion
@AlexisHassler @Antoine_SD#J3E
Extension pourquoi, comment ?
•Pour manipuler les meta données du container :
• AnnotatedType
• InjectionPoint / InjectionTarget
• BeanAttributes/Beans
• Producer
• Observer
!
•En observant les événements déclenchés par CDI lors de l’initialisation du container
@AlexisHassler @Antoine_SD#J3E
Créer une extension CDI
•implémenter l’interface de marquage javax.enterprise.inject.spi.Extension !
•Ajouter une ou plusieurs methotdes qui « observent » les événements déclenchés par le conteneur au démarrage. !
•Déclarer le service provider en ajoutant le fichier: META-INF/services/javax.enterprise.inject.spi.Extension
contenant le nom de la classe d’extension
@AlexisHassler @Antoine_SD#J3E
public interface ProcessAnnotatedType<X> {! public AnnotatedType<X> getAnnotatedType(); public void setAnnotatedType(AnnotatedType<X> type); public void veto();} !
public interface AnnotatedType<X> extends Annotated { public Class<X> getJavaClass(); public Set<AnnotatedConstructor<X>> getConstructors(); public Set<AnnotatedMethod<? super X>> getMethods(); public Set<AnnotatedField<? super X>> getFields();}
Par exemple
•On peut observer l’événement ProcessAnnotatedType pour changer les informations d’un type ou forcer le container à ignorer un type
@AlexisHassler @Antoine_SD#J3E
public class VetoEntity implements Extension { /** * Version CDI 1.0 */ public void vetoEntityLegacy(@Observes ProcessAnnotatedType<?> pat) { AnnotatedType at = pat.getAnnotatedType(); if (at.isAnnotationPresent(Entity.class)) pat.veto(); } /** * Version CDI 1.1+ */ public void vetoEntity(@Observes @WithAnnotations({Entity.class})ProcessAnnotatedType<?> pat) { pat.veto(); } }
Ignorer les entités
•Une bonne pratique est d’éviter d’utiliser les entités JPA comme bean CDI (sauf utilisation avancée).
•Cette extension montre comment exclure les entités JPA de l’ensemble des beans découverts.
@AlexisHassler @Antoine_SD#J3E
Les choses à savoir…
•Une fois l’application lancée le BeanManager est en lecture seule (pas de création de Bean au runtime)
• Ne pas confondre Bean (définition) avec Instance de Bean
!
•Les extensions peuvent aussi devenir des Beans (avec quelques restrictions)
@AlexisHassler @Antoine_SD#J3E
Ajouter un Bean au container
•Il existe plusieurs façon d’ajouter un bean à ceux découverts automatiquement au démarrage du container CDI. !
•La méthode la plus simple reste d’ajouter un AnnotatedType à l’ensemble de ceux découverts par CDI.
@AlexisHassler @Antoine_SD#J3E
public class HashMapAsBeanExtension implements Extension{ public void addHashMapAsAnnotatedType(@Observes BeforeBeanDiscovery bbd,BeanManager beanManager) { bbd.addAnnotatedType(beanManager.createAnnotatedType(HashMap.class)); } }
Ajouter d’un Bean HashMap 1/2
•Il suffit d’observer l’événement BeforeBeanDiscovery et ajouter un AnnotatedType créé à partir de la classe HashMap.
•En CDI 1.1+ on peut également observer AfterTypeDiscovery pour décider l’ajout après que tous les types aient été inspectés
@AlexisHassler @Antoine_SD#J3E
@Decorator@Priority(Interceptor.Priority.APPLICATION) public abstract class MapDecorator implements Map{ @Inject @Delegate Map delegate; @Override public Object put(Object key, Object value) { System.out.println("------- Putting Something in the Map -----------"); if ("key".equals(key)) { System.out.println("==== Not adding key key ======"); return null; } return delegate.put(key,value); }}
Ajouter d’un Bean HashMap 2/2
•Une fois que la HashMap est un bean on peut appliquer les services CDI sur celui-ci comme un décorateur.
@AlexisHassler @Antoine_SD#J3E
CDI 1.1 Lifecycle
Before Bean Discovery
Process BeanProcess
Annotated Type
Scan Archive
Application Running
After Deployment Validation
Before Shutdown
Undeploy Application
Process Producer
After Bean Discovery
Process Injection Target
Process Observer Method
Process Injection
Point
Process Bean Attributes
After Type Discovery
événement unique
événements multiples
étape interne
Deployment starts
Bean eligibility
check
@AlexisHassler @Antoine_SD#J3E
Extension scheduler 1/4
•Cet exemple d’extension vient du projet Apache Deltaspike. Le code présenté est une version simplifiée du code d’origine.
•Il s’agit de pouvoir planifier des tâches à partir d’une annotation @Schedule
@AlexisHassler @Antoine_SD#J3E
public class SchedulerExtension implements Extension { private List<Class> foundManagedJobClasses = new ArrayList<Class>(); private Scheduler scheduler; public <X> void findScheduledJobs(@Observes @WithAnnotations({ Scheduled.class }) ProcessAnnotatedType<X> pat) { Class<X> beanClass = pat.getAnnotatedType().getJavaClass(); this.foundManagedJobClasses.add(beanClass); } public <X> void scheduleJobs(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) { initScheduler(afterBeanDiscovery) List<String> foundJobNames = new ArrayList<String>(); for (Class jobClass : this.foundManagedJobClasses) { foundJobNames.add(jobClass.getSimpleName()); this.scheduler.registerNewJob(jobClass); } } public <X> void stopScheduler(@Observes BeforeShutdown beforeShutdown) { if (this.scheduler != null) { this.scheduler.stop(); this.scheduler = null; } } private void initScheduler(AfterBeanDiscovery afterBeanDiscovery) { this.scheduler = new QuartzScheduler(); this.scheduler.start(); } }
Extension scheduler 2/4 (extension code)
@AlexisHassler @Antoine_SD#J3E
CDI 1.1 Lifecycle
Before Bean Discovery
Process BeanProcess
Annotated Type
Scan Archive
Application Running
After Deployment Validation
Before Shutdown
Undeploy Application
Process Producer
After Bean Discovery
Process Injection Target
Process Observer Method
Process Injection
Point
Process Bean Attributes
After Type Discovery
événement unique
événements multiples
étape interne
Deployment starts
Bean eligibility
check
@AlexisHassler @Antoine_SD#J3E
public interface Scheduler<T> { void start(); void stop(); void pauseJob(Class<? extends T> jobClass); void resumeJob(Class<? extends T> jobClass); void interruptJob(Class<? extends T> jobClass); boolean isExecutingJob(Class<? extends T> jobClass); void registerNewJob(Class<? extends T> jobClass); void startJobManually(Class<? extends T> jobClass); <S> S unwrap(Class<? extends S> schedulerClass);}
Extension scheduler 3/4 (scheduler interface)
@AlexisHassler @Antoine_SD#J3E
@ApplicationScopedpublic class SchedulerProducer{ @Inject private SchedulerExtension schedulerExtension; @Produces @ApplicationScoped protected Scheduler produceScheduler() { return this.schedulerExtension.getScheduler(); }}
Extension scheduler 4/4 (scheduler producer)
@YourTwitterHandle#DVXFR14{session hashtag} @AlexisHassler @Antoine_SD#J3E
JCA
@AlexisHassler @Antoine_SD#J3E
Java Connector
Architecture
@AlexisHassler @Antoine_SD#J3E
Java EE
EISApp
Con
nect
or
Java EE
@AlexisHassler @Antoine_SD#J3E
Java EE
MQTT BrokerApp
Con
nect
or
Java EE / IoT
@AlexisHassler @Antoine_SD#J3E
Outbound !
@AlexisHassler @Antoine_SD#J3E
Java EE
App
Con
nect
or
@AlexisHassler @Antoine_SD#J3E
Resources
• Relational Databases
• Transaction Processing System (CICS, Tuxedo,…)
• Enterprise Resource Planning (SAP, Oracle Applications,…)
• …
@AlexisHassler @Antoine_SD#J3E
Java EE
App
Dat
aSou
rce
@AlexisHassler @Antoine_SD#J3E
public class SomeNiceBean { @Resource DataSource dataSource; public void doTheJob() { Connection connection = dataSource.getConnection(); ... }}
@AlexisHassler @Antoine_SD#J3E
Services communs
•Pooling
•Transactions (Local / XA)
•Sécurité
•…
@AlexisHassler @Antoine_SD#J3E
public class SomeNiceBean { @Resource(name="mqtt/AnswerCF") ConnectionFactory connectionFactory; public void doTheJob() { Connection connection = connectionFactory.getConnection(); ... }}
@AlexisHassler @Antoine_SD#J3E
Inbound !
@AlexisHassler @Antoine_SD#J3E
Java EE
App
Con
nect
or
@AlexisHassler @Antoine_SD#J3E
Message Driven
Bean
@AlexisHassler @Antoine_SD#J3E
Java EE
MDBJMS
Destination
Con
nect
or
@AlexisHassler @Antoine_SD#J3E
JMS Message Driven Bean
@MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName="destinationLookup", propertyValue="swt/Question"), @ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"), }) public class MyJmsBean implements MessageListener { @Override public void onMessage(Message message) { ... } }
@AlexisHassler @Antoine_SD#J3E
Java EE
MDBJMS
Destination
Con
nect
or
@AlexisHassler @Antoine_SD#J3E
@MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"), @ActivationConfigProperty(propertyName="destination", propertyValue="/queue/source"), @ActivationConfigProperty(propertyName="jndiParameters", propertyValue="java.naming.factory.initial=..."), @ActivationConfigProperty(propertyName="connectionFactory", propertyValue="XAConnectionFactory") }) @ResourceAdapter("generic-jms-ra.rar") public class MyJmsBean implements MessageListener { @Override public void onMessage(Message message) { ... } }
Generic JMS Message Driven Bean
https://github.com/jms-ra/generic-jms-ra
@AlexisHassler @Antoine_SD#J3E
Java EE
MDB
! $ Telnet $ Console
Con
nect
or
https://github.com/dblevins/mdb-improvements
@AlexisHassler @Antoine_SD#J3E
Java EE
MDB!!
Topic
Con
nect
or
https://github.com/hasalex/mqtt-ra
@AlexisHassler @Antoine_SD#J3E
@MessageDriven( activationConfig = { @ActivationConfigProperty(propertyName="topicName", propertyValue="swt/Question") } ) public class MyMqttBean implements MqttListener { @Override public void onMessage(Message message) { ... } }
MQTT Message Driven Bean
@AlexisHassler @Antoine_SD#J3E http://pixabay.com/fr/des-animaux-asie-bleu-sombre-18719/
@AlexisHassler @Antoine_SD#J3E
@AlexisHassler @Antoine_SD#J3E
MQTT
•MQ Telemetry Transport
Broker
Consumer
Consumer
Consumer
Producer
Producer
Producer
Topic
Topic
Topic
Topic
SubscribePublish
@AlexisHassler @Antoine_SD#J3E
MQTT
1999
2013
@AlexisHassler @Antoine_SD#J3E
MQTT
http://commons.wikimedia.org/wiki/File:St_Jude_Medical_pacemaker_with_ruler.jpg
@AlexisHassler @Antoine_SD#J3E
MQTT
@AlexisHassler @Antoine_SD#J3E
MQTT / IoT
•Embedded device
• limited processor
• limited memory resources
• energy saving
!
•Network
• Limited bandwidth
• Unreliable network
@AlexisHassler @Antoine_SD#J3E
MQTT QoS
•0 = At most once • Fire and forget
• Message loss can occur
•1 = At least once • Acknowledged delivery
• Duplicates may occur
•2 = Exactly once • Assured delivery
@AlexisHassler @Antoine_SD#J3E
MQTT Client - SubscribeMQTT mqtt = new MQTT(); mqtt.setHost(Settings.SERVER_URL); CallbackConnection connection = mqtt.callbackConnection(); connection.listener(new Listener() { public void onPublish(UTF8Buffer topic, Buffer message, Runnable ack) { System.out.println("Message arrived on topic " + …); ack.run(); } });connection.connect(new Callback<Void>() { public void onSuccess(Void value) { connection.subscribe( new Topic[]{new Topic(Settings.TOPIC_NAME, QoS.AT_MOST_ONCE)}, new Callback<byte[]>() {…}});
@AlexisHassler @Antoine_SD#J3E
MQTT Client - Publish
MQTT mqtt = new MQTT(); mqtt.setHost(Settings.SERVER_URL); CallbackConnection connection = mqtt.callbackConnection(); !connection.connect(new Callback<Void>() { public void onSuccess(Void value) { connection.publish(Settings.TOPIC_NAME, "Message".getBytes(), QoS.AT_MOST_ONCE, false, new Callback<Void>(){…}});
@AlexisHassler @Antoine_SD#J3E
M Q T T Outbound Connector
@AlexisHassler @Antoine_SD#J3E
MQTT Connection Factory
public class SomeNiceBean { @Resource(name="mqtt/QuestionCF") ConnectionFactory connectionFactory; public void doTheJob() { connectionFactory.getConnection() .publish(message); }}
@AlexisHassler @Antoine_SD#J3E
Implémentation API
ManagedConnection Factory
ConnectionFactory
ManagedConnectionConnection
Resource Adapter
@AlexisHassler @Antoine_SD#J3E
Managed Connection Factory@ConnectionDefinition (connectionFactory = MqttConnectionFactoryImpl.class, connectionFactoryImpl = MqttConnectionFactoryImpl.class, connection = BlockingConnection.class, connectionImpl = BlockingConnection.class) public class MqttManagedConnectionFactory implements ManagedConnectionFactory, ResourceAdapterAssociation, Serializable { ... }
@AlexisHassler @Antoine_SD#J3E
Managed Connection Factory @Override public ManagedConnection createManagedConnection (Subject subject, ConnectionRequestInfo cxRequestInfo) throws ResourceException { return new MqttManagedConnection(cxRequestInfo); }
@AlexisHassler @Antoine_SD#J3E
Managed Connection Factory @Override public ManagedConnection matchManagedConnections (Set connectionSet, Subject subject, ConnectionRequestInfo cxRequestInfo) throws ResourceException { ... }
Connection Pool
Management
@AlexisHassler @Antoine_SD#J3E
Managed Connection Factory ... public void setServerUrl(String serverUrl) { this.serverUrl = serverUrl; } public void setDefaultQosLevel(int qosLevel) { this.qosLevel = qosLevel; } public void setDefaultTopic(String defaultTopic) { this.defaultTopic = defaultTopic; }
Configuration
@AlexisHassler @Antoine_SD#J3E
Managed Connection Factory ... @Override public Object createConnectionFactory (ConnectionManager cxManager) throws ResourceException { return new MqttConnectionFactoryImpl(this, cxManager); } ...
ConnectionFactory
Factory
@AlexisHassler @Antoine_SD#J3E
Connection Factorypublic class MqttConnectionFactoryImpl implements Referenceable, MqttConnectionFactory { // fields : cxManager, managedConnectionFactory @Override public MqttConnection getConnection() { try { return (MqttConnection) cxManager .allocateConnection(managedConnectionFactory, null); } catch (ResourceException e) { throw new RuntimeException(e); } } ... }
@AlexisHassler @Antoine_SD#J3E
ManagedConnection Factory
ConnectionFactory
new
ManagedConnection
new
ConnectionManager
Connection
ResourceAdapter
new
ConnectionEventListener XAResource
LocalTransaction
ManagedConnectionMetaData
@AlexisHassler @Antoine_SD#J3E
M Q T T Inbound Connector
@AlexisHassler @Antoine_SD#J3E
@MessageDriven( activationConfig = { @ActivationConfigProperty(propertyName = "topicName", propertyValue = "swt/Question") } ) public class MyMqttBean implements MqttListener { @Override public void onMessage(Message message) { ... } }
MQTT Message Driven Bean
@AlexisHassler @Antoine_SD#J3E
ResourceAdapterListener
ActivationSpecMessage
XAResource
WorkerManager
BootstrapContext
@AlexisHassler @Antoine_SD#J3E
Connector API
public interface MqttListener { void onMessage(Message message); }
public class Message { private byte[] payload; public Message(byte[] payload) { this.payload = payload; } // + Getter}
@AlexisHassler @Antoine_SD#J3E
Connector Implementation
@Connector( vendorName = "sewatech", version = "0.1", eisType = "MQTT Inbound Adapter", transactionSupport = NoTransaction) public class MqttAdapter implements ResourceAdapter { ... }
Lifecycle
http://commons.wikimedia.org/wiki/File:Drohnenpuppen_81b.jpg
@AlexisHassler @Antoine_SD#J3E
EndpointStarted
Stopped
start()stop()
Activated
Deactivated
endpointActivation()endpointDeactivation()
Lifecycle
@AlexisHassler @Antoine_SD#J3E
Lifecycle
public class MqttAdapter implements ResourceAdapter {! public void start(BootstrapContext bootstrapContext) throws ResourceAdapterInternalException { ... } ! public void stop() { ... } ... }
@AlexisHassler @Antoine_SD#J3E
Connector / Endpoints
public class MqttAdapter implements ResourceAdapter { ... public void endpointActivation(MessageEndpointFactory factory, ActivationSpec activationSpec) throws ResourceException { ... } public void endpointDeactivation(MessageEndpointFactory factory, ActivationSpec activationSpec) { ... } }
@AlexisHassler @Antoine_SD#J3E
Endpoint Activation
public void endpointActivation (MessageEndpointFactory mdbFactory, ActivationSpec activationSpec) throws ResourceException { ActivationSpecBean spec = (ActivationSpecBean) activationSpec; MqttListener mdb = (MqttListener) mdbFactory.createEndpoint(null); ! MQTT mqtt = new MQTT(); // Connexion via le client MQTT... }
Pool
http://www.flickr.com/photos/gingerfuhrer/2883491950/
@AlexisHassler @Antoine_SD#J3E
Pool
Java EE
!!
TopicMDB
Con
nect
or
@AlexisHassler @Antoine_SD#J3E
@MessageDriven( activationConfig = { @ActivationConfigProperty(propertyName = "topicName", propertyValue = "swt/Question"), @ActivationConfigProperty(propertyName = "poolSize", propertyValue = "10") } ) public class MyMqttBean implements MqttListener { @Override public void onMessage(Message message) { ... } }
Pool
@AlexisHassler @Antoine_SD#J3E
Pool
public void endpointActivation (MessageEndpointFactory mdbFactory, ActivationSpec activationSpec) throws ResourceException { BlockingQueue<MqttMessageListener> pool = new ArrayBlockingQueue<>(poolSize); for (int i = 0; i < poolSize; i++) { pool.add(mdbFactory.createEndpoint(null))); } ... }
Threads
https://www.flickr.com/photos/mckaysavage/6491930649/
@AlexisHassler @Antoine_SD#J3E
Threadspublic void endpointActivation (MessageEndpointFactory mdbFactory, ActivationSpec activationSpec) throws ResourceException { ... WorkManager workManager = bootstrapContext.getWorkManager() workManager.startWork(new Work() { @Override public void run() { } @Override public void release() { } }); ... }
@AlexisHassler @Antoine_SD#J3E
MQTT Broker
WS
Connector !
mqtt-ra.rar
Application (w. MDB)
mqtt-ra-example.warMQTT Client
JS
@AlexisHassler @Antoine_SD#J3E
@MessageDrivenpublic class MyMqttBean implements MqttListener { @TopicName("swt/Question") public void onQuestion(Message message) { ... } ! @TopicName("swt/Answer") public void onAnswer(Message message) { ... } !}
Message Driven Bean ++
@AlexisHassler @Antoine_SD#J3E
Connector !
mqtt-ra.rar
Application (w. MDB)
mqtt-ra-example.war MQTT Broker
(mosquitto)
MQTT Client mosquitto pub/sub
@YourTwitterHandle#DVXFR14{session hashtag} @AlexisHassler @Antoine_SD#J3E
JCA
//
CDI
@AlexisHassler @Antoine_SD#J3E
CDI
JCA
@AlexisHassler @Antoine_SD#J3E
Managed Connection Factory@ConnectionDefinition (connectionFactory = MqttConnectionFactoryImpl.class, connectionFactoryImpl = MqttConnectionFactoryImpl.class, connection = BlockingConnection.class, connectionImpl = BlockingConnection.class) public class MqttManagedConnectionFactory implements ManagedConnectionFactory, ResourceAdapterAssociation, Serializable { @Inject ResourceAdapter ra; !}
@AlexisHassler @Antoine_SD#J3E
JCA
CDI
@AlexisHassler @Antoine_SD#J3E
public class SomeNiceBean { @Inject MqttConnectionFactory connectionFactory; public void doTheJob() { Connection connection = connectionFactory.getConnection(); ... }}
!javax.enterprise.inject.
UnsatisfiedResolutionException
@AlexisHassler @Antoine_SD#J3E
public class SomeNiceBean { @Inject MqttConnectionFactory connectionFactory; public void doTheJob() { Connection connection = connectionFactory.getConnection(); ... }}
public class MqttResourceProducer {! @Produces @Resource(name="mqtt/AnswerCF") private MqttConnectionFactory answerConnectionFactory; }
@AlexisHassler @Antoine_SD#J3E
Java EE 8
•Implicit Producers ?
•Ambiguities ?
•Qualifiers ?
@AlexisHassler @Antoine_SD#J3E
public class SomeNiceBean { @Inject @Answer MqttConnectionFactory connectionFactory; public void doTheJob() { Connection connection = connectionFactory.getConnection(); ... }}
public class MqttResourceProducer { @Produces @Answer @Resource(name="mqtt/AnswerCF") private MqttConnectionFactory answerConnectionFactory; }
@AlexisHassler @Antoine_SD#J3E
!
JCA // CDI
@AlexisHassler @Antoine_SD#J3E
JCA UserTransaction
Concurrency Service
ManagedConnection Factory
ConnectionFactory
new
ManagedConnection
new
ConnectionManager
Connection
ResourceAdapter
new
ConnectionEventListener XAResource
LocalTransaction
ManagedConnectionMetaData
WorkerManager
@AlexisHassler @Antoine_SD#J3E
CDI UserTransaction
ManagedExecutor Service
ConnectionFactory Producer
ConnectionFactory
new
ConnectionLocalTransaction
@AlexisHassler @Antoine_SD#J3E
Outbound Connector !
JCA < CDI
@AlexisHassler @Antoine_SD#J3E
@MessageDriven( activationConfig = { @ActivationConfigProperty(propertyName = "topicName", propertyValue = "swt/Question") } ) public class MyMqttBean implements MqttListener { @Override public void onMessage(Message message) { ... } }
Message Driven Bean
@AlexisHassler @Antoine_SD#J3E
@MqttDrivenpublic class MyMqttBean { @TopicName("swt/Question") public void onQuestion(Message message) { ... } ! @TopicName("swt/Answer") public void onAnswer(Message message) { ... } !}
Message Driven Bean
@AlexisHassler @Antoine_SD#J3E
Inbound Connector !
JCA > CDI
@AlexisHassler @Antoine_SD#J3E
Java EE Application Server
App
CDI
App
CDI
App
CDI
JCA
@AlexisHassler @Antoine_SD#J3E
?http://pixabay.com/fr/point-d-interrogation-boule-demande-65833/
@AlexisHassler @Antoine_SD#J3E
Exemples
!
!
•https://github.com/antoinesd/cdi-demo !
•https://github.com/hasalex/mqtt-ra