Fais ce que tu veux avec Java EE - Devoxx France 2014

Post on 10-May-2015

1.602 views 7 download

Tags:

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.

Transcript of Fais ce que tu veux avec Java EE - Devoxx France 2014

@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://www.galuzzi.it/

@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