Esistono in giro soluzioni Open Source di ogni tipo che implementano Enterprise Service Bus (ESB), Liferay ha preferito non integrare al suo interno una delle soluzioni esistenti (il più delle volte pensanti) in favore di un proprio “piccolo message bus” che fosse in grado di far comunicare in modo semplificato i componenti del portale tramite lo scambio di messaggi. La versione 6.1 di Liferay ha migliorato di molto il Message Bus introducendo un più ricco insieme di service API che facilitano lo scambio dei messaggi tra le portlet e in generale tra i plugins.
1. Antonio
Musarra's
Blog
Document Revision:1.0-IT
The
ideal
solution
for
a
problem
Blog:
http://musarra.wordpress.com
LinkedIn:
http://it.linkedin.com/in/amusarra
Mail:
antonio.musarra@gmail.com
23/04/13
1
This
document
is
issued
with
license
Creative
Commons
Attribution-‐NonCommercial-‐ShareAlike
Introduzione
a
Liferay
Message
BUS
Esistono
in
giro
soluzioni
Open
Source
di
ogni
tipo
che
implementano
Enterprise
Service
Bus
(ESB),
Liferay
ha
preferito
non
integrare
al
suo
interno
una
delle
soluzioni
esistenti
(il
più
delle
volte
pensanti)
in
favore
di
un
proprio
“piccolo
message
bus”
che
fosse
in
grado
di
far
comunicare
in
modo
semplificato
i
componenti
del
portale
tramite
lo
scambio
di
messaggi.
La
versione
6.1
di
Liferay
ha
migliorato
di
molto
il
Message
Bus
introducendo
un
più
ricco
insieme
di
service
API
che
facilitano
lo
scambio
dei
messaggi
tra
le
portlet
e
in
generale
tra
i
plugins.
1. Utilizzo
del
Message
Bus
I
messaggi
scambiati
all’interno
di
Liferay
tramite
il
Message
Bus,
sono
esclusivamente
di
tipo
String
(in
genere
il
formato
adottato
è
JSON),
così
facendo
l’accoppiamento
tra
producers
e
consumers
è
ancora
più
ridotto
e
inoltre
sono
evitati
i
problemi
di
caricamento
delle
classi.
Il
Message
Bus
è
situato
all’interno
del
kernel
di
Liferay,
in
questo
modo
sarà
possibile
accedere
ai
servizi
del
Bus
da
ogni
applicazione
installata.
L’implementazione
attuale
non
consente
di
inviare
messaggi
remoti
che
comunque
possono
essere
inviati
attraverso
il
cluster
utilizzando
le
classi
ClusterLink.
A
qualcuno
potrebbero
venire
in
mente
delle
somiglianze
con
Java
Message
Service
(JMS),
il
Message
Bus
di
Liferay
è
molto
più
semplice
e
non
fornisce
tutte
le
caratteristiche
della
specifica
JMS.
Quanto
mostrato
in
Figura
1
è
una
rappresentazione
degli
usi
comuni
del
Message
Bus.
Figura
1.
Usi
comuni
del
Message
Bus
all’interno
di
Liferay
Un
esempio
tangibile
d’uso
del
Message
Bus
è
appunto
la
portlet
Message
Board,
questa,
invia
il
messaggio
sul
bus
restituendo
la
risposta
all’utente,
che
può
continuare
a
interagire
con
il
portale.
Chi
riceve
il
messaggio
dal
bus
(il
listener),
esegue
una
serie
di
azioni
sul
messaggio
(nel
caso
di
sottoscrizioni
l’azione
corrisponde
all’invio
di
un’email
a
tutti
i
sottoscritti
al
messaggio)
utilizzando
un
thread
separato.
2. Antonio
Musarra's
Blog
Document Revision:1.0-IT
The
ideal
solution
for
a
problem
Blog:
http://musarra.wordpress.com
LinkedIn:
http://it.linkedin.com/in/amusarra
Mail:
antonio.musarra@gmail.com
23/04/13
2
This
document
is
issued
with
license
Creative
Commons
Attribution-‐NonCommercial-‐ShareAlike
2. Architettura
del
Message
Bus
Sono
quattro
i
“pezzi”
fondamentali
che
costituisco
il
Message
Bus
di
Liferay
e
sono:
• Message
Bus:
Gestisce
il
canale
di
trasporto
dei
messaggi
garantendo
la
consegna
degli
stessi
dai
senders
ai
listeners;
• Destinations:
Sono
gli
indirizzi
o
destinazioni
alle
quali
i
listeners
sono
registrati
affinchè
possano
ricevere
i
messaggi;
• Listeners:
Sono
i
”consumatori”
dei
messaggi
ricevuti
nelle
destinazioni.
Questi
ricevono
tutti
i
messaggi
inviati
alle
loro
destinazioni
registrate;
• Senders:
Chi
invia
i
messaggi
sul
bus
verso
una
destinazione
registrata.
E’
possibile
per
cui
inviare
dei
messaggi
a
una
o
più
destinazioni
e
inoltre
possibile
configurare
listener
in
ascolto
su
una
o
più
destinazioni.
Tanto
per
fare
un
esempio
potremmo
avere
una
situazione
di
questo
tipo:
• Un
client
invia
un
messaggio
a
una
destinazione
chiamata
shirusLabs/HorseGallops;
• Il
Message
Bus
esegue
un’interazione
con
ogni
listener
registrato
sulla
destinazione
shirusLabs/HorseGallops;
• Per
ogni
listener
è
chiamato
il
metodo
receive(String
message).
Lo
schema
illustrato
in
Figura
2
è
un
possibile
scenario
d’utilizzo
del
Message
Bus
che
chiarirà
ancor
di
più
le
idee
sull’architettura.
Da
notare
come
un
servizio
può
inviare
messaggi
a
una
o
più
destinazioni
e
come
un
listener
può
essere
in
ascolto
su
più
destinazioni,
oltre
al
fatto
che
un
servizio
può
essere
sia
sender
sia
listener.
Figura
2.
Possibile
scenario
utilizzo
del
Message
Bus
3. Antonio
Musarra's
Blog
Document Revision:1.0-IT
The
ideal
solution
for
a
problem
Blog:
http://musarra.wordpress.com
LinkedIn:
http://it.linkedin.com/in/amusarra
Mail:
antonio.musarra@gmail.com
23/04/13
3
This
document
is
issued
with
license
Creative
Commons
Attribution-‐NonCommercial-‐ShareAlike
Anche
il
Message
Bus
di
Liferay
come
il
resto
delle
altre
soluzioni
supporta
principalmente
due
tipologie
di
messaggio:
• Synchronous
messaging:
Dopo
l’invio
di
un
messaggio,
il
mittente
rimane
in
attesa
di
una
risposta
da
parte
del
destinatario;
• Asynchronous
messaging:
Dopo
l’invio
di
un
messaggio,
il
mittente
è
libero
di
continuare
l’elaborazione.
Il
mittente
può
essere
configurato
per
ricevere
una
call-‐back
o
può
semplicemente
“inviare
e
dimenticare
(Send-‐and-‐Forget)”.
o Call-‐Back:
Il
mittente
può
essere
configurato
in
modo
tale
che
sia
richiamato
dal
destinatario.
o Send-‐and-‐Forget:
Il
mittente
non
include
nel
messaggio
informazioni
di
call-‐back
e
continua
semplicemente
con
l’elaborazione.
Tutti
gli
elementi
del
Message
Bus
(destinations,
listeners
e
mapping
tra
loro)
sono
magicamente
configurabili
tramite
Spring.
La
configurazione
del
Message
Bus
è
realizzata
attraverso
i
seguenti
file
XML:
• WEB-‐INF/src/META-‐INF/messaging-‐spring.xml:
All’interno
di
questo
file
devono
essere
definite
le
destinazioni,
listeners
e
il
mapping
tra
di
loro;
• WEB-‐INF/web.xml
:
Contiene
la
lista
dei
deployment
descriptors
del
plugin,
in
più
occorre
aggiungere
alla
lista
anche
il
file
di
configurazione
messaging-‐spring.xml
di
Spring.
Ogni
listener
definito
in
configurazione
(fare
riferimento
a
WEB-‐
INF/src/META-‐INF/messaging-‐spring.xml)
deve
implementare
l’interfaccia
base
MessageListener
(com.liferay.portal.kernel.messaging.MessageListener)
sov
rascrivendo
il
metodo
(vedi
Figura
3):
• public
void
receive(Message
message)
throws
MessageListenerException
Figura
3.
Class
Diagram
Message
Listener
4. Antonio
Musarra's
Blog
Document Revision:1.0-IT
The
ideal
solution
for
a
problem
Blog:
http://musarra.wordpress.com
LinkedIn:
http://it.linkedin.com/in/amusarra
Mail:
antonio.musarra@gmail.com
23/04/13
4
This
document
is
issued
with
license
Creative
Commons
Attribution-‐NonCommercial-‐ShareAlike
Liferay
fornisce
una
“facility”
class
astratta
BaseMessageListener
che
implementa
il
metodo
receive()
dell’interfaccia
MessageListener
fornendo
un
metodo
astratto
doReceive(),
il
vostro
listener
può
quindi
estendere
direttamente
la
classe
BaseMessageListener
implementando
il
metodo
doReceive().
Nelle
figure
a
seguire
sono
mostrati
i
sequence
diagram
delle
due
tipologie
di
messaggi:
sincroni
e
asincroni.
Figura
4.
Messaggio
Sincrono
Dalla
Figura
5
e
Figura
6
è
possibile
notare
che
ci
sono
due
tipi
di
destinations
per
messaggi
di
tipo
asincrono:
• Parallel
Destination:
Utilizzato
nei
casi
in
cui
i
messaggi
devono
essere
inviati
in
parallelo.
Su
questo
tipo
di
destinazione
è
possibile
agire
sulla
configurazione
del
Thread
Pool
(Asynchronous
“Send
and
Forget”
vedi
Figura
6);
• Serial
Destination:
Utilizzato
nel
caso
in
cui
le
richieste
devono
essere
inviate
in
serie.
In
questo
caso
la
dimensione
del
Thread
Pool
è
impostata
a
uno
(Asynchronous
con
callbacks
vedi
Figura
5).
Figura
5.
Messaggio
Asincrono
con
invio
seriale
5. Antonio
Musarra's
Blog
Document Revision:1.0-IT
The
ideal
solution
for
a
problem
Blog:
http://musarra.wordpress.com
LinkedIn:
http://it.linkedin.com/in/amusarra
Mail:
antonio.musarra@gmail.com
23/04/13
5
This
document
is
issued
with
license
Creative
Commons
Attribution-‐NonCommercial-‐ShareAlike
Figura
6.
Messaggio
Asincrono
con
invio
parallelo
In
Figura
7
è
invece
indicato
il
class
diagram
che
mostra
le
relazioni
tra
i
tipi
di
destinazione
implementati
dal
Message
Bus
di
Liferay.
Figura
7.
Relazioni
tra
i
tipi
di
destinazione
6. Antonio
Musarra's
Blog
Document Revision:1.0-IT
The
ideal
solution
for
a
problem
Blog:
http://musarra.wordpress.com
LinkedIn:
http://it.linkedin.com/in/amusarra
Mail:
antonio.musarra@gmail.com
23/04/13
6
This
document
is
issued
with
license
Creative
Commons
Attribution-‐NonCommercial-‐ShareAlike
3. Configurazione
Nel
precedente
paragrafo
abbiamo
visto
quali
sono
gli
elementi
che
ruotano
nell’intorno
del
Message
Bus
e
qual
è
il
file
di
configurazione
tramite
il
quale
è
possibile
configurare
ogni
singolo
elemento.
Potremmo
suddividere
la
configurazione
per
sezioni,
quali:
• Listeners:
in
questa
sezione
devono
essere
specificate
una
o
più
classi
che
gestiscono
i
messaggi
che
transitano
sul
Message
Bus
verso
una
o
più
destinazioni;
• Destinations:
in
questa
sezione
devono
essere
specificate
una
o
più
destinazioni
dichiarando
il
tipo
e
il
nome;
• Configurator:
in
questa
sezione
devono
essere
specificate
le
relazioni
destinazione
=>
listener.
A
titolo
esemplificativo
sono
mostrati
a
seguire
le
tre
sezioni
di
configurazione
di
ogni
elemento
del
Message
Bus.
Come
potete
notare
la
configurazione
è
in
puro
stile
Spring.
<!– Listeners –>
<bean id="messageListener.marketing_listener"
class="it.dontesta.crm.messaging.impl.MarketingMessagingImpl" />
<bean id="messageListener.sales_listener"
class="it.dontesta.crm.messaging.impl.SalesMessagingImpl" />
<bean id="messageListener.customer_support_listener"
class="it.dontesta.crm.messaging.impl.CustomerSupportMessagingImpl" />
Source
1.
Configurazione
listener
La
configurazione
indicata
al
Source
1
dichiara
tre
diversi
listener
ognuno
dei
quali
è
una
classe
che
implementa
l’interfaccia
MessageListener
o
estende
la
classe
astratta
BaseMessageListener.
<!-- Destinations -->
<bean id="destination.crm.customer.ticket"
class="com.liferay.portal.kernel.messaging.SynchronousDestination">
<property name="name" value="crm/customer/support/ticket"/>
</bean>
<bean id="destination.crm.customer.ticket.response"
class="com.liferay.portal.kernel.messaging.SynchronousDestination">
<property name="name" value="crm/customer/support/ticket/response"/>
</bean>
<bean id="destination.crm.marketing.lead"
class="com.liferay.portal.kernel.messaging.SerialDestination">
<property name="name" value="crm/marketing/lead"/>
</bean>
<bean id="destination.crm.marketing.lead"
class="com.liferay.portal.kernel.messaging.SynchronousDestination">
<property name="name" value="crm/marketing/lead/response"/>
</bean>
<bean id="destination.crm.marketing.stream"
class="com.liferay.portal.kernel.messaging.ParallelDestination">
<property name="name" value="crm/marketing/stream"/>
</bean>
Source
2.
Configurazione
destinazioni
7. Antonio
Musarra's
Blog
Document Revision:1.0-IT
The
ideal
solution
for
a
problem
Blog:
http://musarra.wordpress.com
LinkedIn:
http://it.linkedin.com/in/amusarra
Mail:
antonio.musarra@gmail.com
23/04/13
7
This
document
is
issued
with
license
Creative
Commons
Attribution-‐NonCommercial-‐ShareAlike
La
configurazione
indicata
al
Source
2
dichiara
le
destinazioni
specificandone
il
tipo
e
il
nome
della
destinazione.
Il
tipo
indica
la
classe
che
implementa
la
Destination
(vedi
class
diagram
di
Figura
7).
Le
destination
supportate
sono
implementate
dalle
seguenti
classi:
• com.liferay.portal.kernel.messaging.SynchronousDestination:
per
messaggio
di
tipo
sincrono;
• com.liferay.portal.kernel.messaging.SerialDestination:
per
messaggio
di
tipo
asincrono
con
call-‐back;
• com.liferay.portal.kernel.messaging.ParallelDestination:
per
messaggio
di
tipo
asincrono
send-‐and-‐forget.
Il
nome
della
destinazione
(vedi
Source
2
riga
4)
identifica
questa
all’interno
del
Message
Bus
e
deve
essere
univoco;
il
nome
assegnato
deve
essere
a
conosciuto
dal
consumer
del
servizio.
<!-- Configurator -->
<bean id="messagingConfigurator"
class="com.liferay.portal.kernel.messaging.config.PluginMessagingConfigurator">
<property name="messageListeners">
<map key-type="java.lang.String" value-type="java.util.List">
<entry key="crm/customer/support/ticket">
<list value-
type="com.liferay.portal.kernel.messaging.MessageListener">
<ref bean="messageListener.customer_support_listener"/>
</list>
</entry>
<entry key="crm/customer/support/ticket/response">
<list value-
type="com.liferay.portal.kernel.messaging.MessageListener">
<ref bean="messageListener.customer_support_listener"/>
</list>
</entry>
<entry key="crm/marketing/lead">
<list value-
type="com.liferay.portal.kernel.messaging.MessageListener">
<ref bean="messageListener.marketing_listener"/>
</list>
</entry>
</map>
</property>
<property name="destinations">
<list>
<ref bean="destination.crm.customer.ticket"/>
<ref bean="destination.crm.customer.ticket.response"/>
<ref bean="destination.crm.marketing.lead"/>
<ref bean="destination.crm.marketing.lead.response"/>
</list>
</property>
</bean>
Source
3.
Configurazione
mapping
destinazioni
=>
listener
8. Antonio
Musarra's
Blog
Document Revision:1.0-IT
The
ideal
solution
for
a
problem
Blog:
http://musarra.wordpress.com
LinkedIn:
http://it.linkedin.com/in/amusarra
Mail:
antonio.musarra@gmail.com
23/04/13
8
This
document
is
issued
with
license
Creative
Commons
Attribution-‐NonCommercial-‐ShareAlike
La
configurazione
indicata
al
Source
3
specifica
le
relazioni
tra
destinazione
e
listener.
Le
relazioni
possibili
sono
quelle
indicate
in
Figura
2.
La
configurazione
core
del
Message
Bus
di
Liferay
è
disponibile
sul
file
messaging-‐
core-‐spring.xml
invece
il
file
messaging-‐misc-‐spring.xml
contiene
le
configurazioni
di
destination
e
listener
dei
componenti
di
“serie”
di
Liferay,
alcune
delle
destinazioni
sono:
• liferay/subscription_sender
• liferay/message_boards_mailing_list
• liferay/document_library_pdf_processor
Nel
prossimo
paragrafo
vedremo
un
semplice
esempio
di
come
spedire
delle
notifiche
via
email
inviando
un
messaggio
verso
la
destinazione
liferay/subscription_sender.
4. Invio
messaggi
sul
Message
Bus
Inviare
un
messaggio
sul
Message
Bus
e
verso
una
specifica
destinazione
è
molto
semplice
tramite
il
set
di
API
a
disposizione.
Supponiamo
il
caso
di
voler
inviare
una
o
più
notifiche
via
mail
da
una
delle
nostre
portlet,
per
questo
dovremmo
preparare
un
messaggio
con
il
contenuto
della
notifica
e
destinatari,
in
seguito
inviare
il
messaggio
verso
la
destinazione
liferay/subscription_sender.
In
questo
caso
la
destinazione
è
di
tipo
ParallelDestination
(fare
riferimento
alla
configurazione
definita
in
messaging-‐misc-‐spring.xml),
stiamo
parlando
quindi
di
un
messaggio
Asincrono
(Send-‐and-‐Forget).
L’estratto
di
codice
mostrato
al
Source
4
in
breve:
• Prepara
l’oggetto
di
tipo
SubscriptionSender
contenente
il
testo
dell’email
e
destinatari;
• Crea
il
messaggio
da
inviare
sul
Message
Bus
specificando
la
destinazione
e
il
contenuto
informativo,
quest’ultimo
rappresentato
dall’oggetto
subscriptionSender
(Serializable);
• Invia
il
messaggio
appena
creato
sul
Message
Bus,
questo
consegnerà
il
messaggio
alla
destinazione
indicata.
SubscriptionSender subscriptionSender = new SubscriptionSender();
subscriptionSender.setSubject("Test invio email via Message Bus");
subscriptionSender.setBody("Ecco la mail via Message Bus");
subscriptionSender.setUserId(user.getUserId());
subscriptionSender.addRuntimeSubscribers(
user.getEmailAddress(),
user.getFullName());
Message myMessage = new Message();
myMessage.setDestinationName("liferay/subscription_sender");
myMessage.setPayload(subscriptionSender);
MessageBusUtil.sendMessage(myMessage.getDestinationName(), myMessage);
Source
4.
Esempio
d’invio
email
via
Message
Bus
(MessageBusExample.java)
9. Antonio
Musarra's
Blog
Document Revision:1.0-IT
The
ideal
solution
for
a
problem
Blog:
http://musarra.wordpress.com
LinkedIn:
http://it.linkedin.com/in/amusarra
Mail:
antonio.musarra@gmail.com
23/04/13
9
This
document
is
issued
with
license
Creative
Commons
Attribution-‐NonCommercial-‐ShareAlike
Il
messaggio
inviato
sul
Message
Bus
e
destinato
a
liferay/subscription_sender
è
elaborato
dal
listener
SubscriptionSenderMessageListener
che
effettivamente
invia
la
mail.
Sul
mio
repository
GitHub
l’esempio
completo
della
portlet
che
interagisce
con
il
Message
Bus.
5. Conclusioni
Sono
partito
con
l’intenzione
di
scrivere
una
serie
d’articoli
che
trattano
il
Message
Bus
di
Liferay.
Con
questo
primo
articolo
della
serie
ho
voluto
introdurre
le
caratteristiche
fondamentali
di
questo
strumento
evidenziando
i
principali
vantaggi
e
in
particolare
la
semplicità
in
termini
d’uso
e
configurazione.
Forse
qualcuno
potrebbe
pensare
che
ho
terminato
con
un
semplice
esempio,
ho
comunque
in
serbo
per
il
prossimo
articolo
un
caso
di
studio
molto
più
interessante:
Il
Message
Bus
come
mezzo
d’integrazione
verso
altri
sistemi.