#LRIS2014 - MessageBus, Cluster communication and Caching on B2B

48
MessageBus, Cluster communication and caching on B2B Mariuzzo Mauro Liferay Architect, SMC Treviso srl

Transcript of #LRIS2014 - MessageBus, Cluster communication and Caching on B2B

MessageBus, Cluster communication and caching on B2B

Mariuzzo MauroLiferay Architect, SMC Treviso srl

Liferay Symposium Italy, Rome 2014- 2 -

Requisito

Creare una soluzione B2B per consentire a Partner e Rivenditori di:● vedere il catalogo dei prodotti● effettuare ordini e vederne lo stato di

avanzamento● vedere i propri documenti fiscali (ordini,

fatture)

Liferay Symposium Italy, Rome 2014- 4 -

Prodotti coinvolti - ERP

Fonte aziendale autoritativa per:● Anagrafiche Cliente, Anagrafiche Prodotto, ...● Lavorazioni● Ordini● Fatture● Listini Particolari Cliente e metodi di calcolo del prezzo● Contratti e Promozioni● ....

ERP

Liferay Symposium Italy, Rome 2014- 5 -

Soluzione CRM open source realizzata in Java secondo un paradigma model-driven.

Gestisce le problematiche CRM, SFA, MA.

Implementa diversi meccanismi di integrazione: CalDAV, CardDAV, IMAP, LDAP, ...

Prodotti coinvolti - CRM

OpenCRX

Liferay Symposium Italy, Rome 2014- 6 -

Replica i dati ERP e li arricchisce per i contesti “non fiscali”:● Customer Satisfaction (Help-Desk, TTS, ....)● Sales Force Automation● Marketing Automation● ....

Prodotti coinvolti - CRM

OpenCRX

Liferay Symposium Italy, Rome 2014- 7 -

● Fornisce all'utente una User Interface semplificata che migliora la sua User eXperience– Rispetto a ERP e CRM

● Unico punto di accesso applicativo per gli utenti esterni● Moltiplicatore di accessi

– I CRM non sono pensati per centinaia di utenti contemporanei

● Arricchisce i contenuti per una fruizione “responsiva” e cross-browser

● ....

Prodotti coinvolti - Portale

Liferay-Portal

Liferay Symposium Italy, Rome 2014- 8 -

DMZ LAN

Soluzione - Architettura

Internet

Liferay Symposium Italy, Rome 2014- 9 -

Soluzione – Screenshots

Liferay Symposium Italy, Rome 2014- 10 -

Soluzione – Screenshots

Liferay Symposium Italy, Rome 2014- 11 -

Soluzione – Screenshots

Liferay Symposium Italy, Rome 2014- 12 -

Soluzione – Screenshots

Liferay Symposium Italy, Rome 2014- 13 -

Soluzione – Screenshots

Liferay Symposium Italy, Rome 2014- 14 -

Soluzione – Screenshots

Liferay Symposium Italy, Rome 2014- 15 -

Soluzione – Screenshots

Liferay Symposium Italy, Rome 2014- 16 -

DMZ LAN

Soluzione - Architettura

Internet

Liferay Symposium Italy, Rome 2014- 17 -

Problematiche – Integrazione Liferay-CRM

OpenCRX dispone di un ricco set di API REST per accedere alle informazioni ed alle funzionalità

La “soluzione B2B” è composta da diversi plugins (file .war separati)

Come evitare di duplicare il codice di integrazione?

Liferay Symposium Italy, Rome 2014- 18 -

Problematiche – Integrazione Liferay-CRM – plugin shared

Per i servizi SOAP posso generare una “client library” partendo dal wsdl.

Per i servizi REST me la devo costruire.

Con il Liferay Plugins SDK posso realizzare la “client library” come plugin “shared”:● un particolare tipo di plugin che produce “.jar”

invece di “.war”● pensato per codice senza stato (stateless)

Liferay Symposium Italy, Rome 2014- 19 -

Problematiche – Integrazione Liferay–CRM – plugin shared

Esempio: knowledge-base-portlet, knowledge-base-shared

Il file build.xml

<?xml version="1.0"?><!DOCTYPE project>

<project name="knowledge-base-shared" basedir="." default="deploy"><property name="plugin.version" value="1" />

<import file="../build-common-shared.xml" /></project>

Liferay Symposium Italy, Rome 2014- 20 -

Problematiche – Integrazione Liferay–CRM – plugin shared

Il file “build.xml” nel portlet che vuole usare lo shared

<?xml version="1.0"?><!DOCTYPE project>

<project name="knowledge-base-portlet" basedir="." default="deploy"><import file="../build-common-portlet.xml" />

<property name="import.shared" value="knowledge-base-shared" /></project>

Liferay Symposium Italy, Rome 2014- 21 -

Problematiche risolte

✔ Gestire il codice di integrazione con OpenCRX in una libreria riusabile da più plugins

Liferay Symposium Italy, Rome 2014- 22 -

Problematiche – Evitare sovraccarico CRM

Come evitare che tutti i plugin parlino direttamente con il CRM sovraccaricandolo?

Il plugin “shared” non mi aiuta.

Posso usare i service con il required-context!

Liferay Symposium Italy, Rome 2014- 23 -

Liferay Plugins SDK - Required context

● Anche un plugin può dichiarare dei servizi (file service.xml)

● Il servizio si basa su 3 elementi:– L'interfaccia (es: KBArticleService)– La classe di implementazione (es: KBArticleServiceImpl)– La classe singleton (es: KBArticleServiceUtil)

● Interfaccie e singleton finiscono in un file “xxxx-service.jar”

● L'implementazione è caricata in modalità “lazy” tramite Spring

Liferay Symposium Italy, Rome 2014- 24 -

Liferay Plugins SDK - Required context

● Un plugin può dichiarare che vuole usare i servizi usati da un altro plugin– Nel file “liferay-plugin-package.properties”– Proprietà “required-depoyment-contexts”

● A compile-time il file “xxxx-service.jar” viene copiato in “docroot/WEB-INF/lib” e finisce nel .war

● Nella fase di deploy il plugin non viene reso operativo in assenza del contesto richiesto

● Spring crea un tunnel tra i due plugin (i due contesti)● L'infrastruttura Liferay permette di trasferire oggetti

complessi senza ClassCastExcpetion

Liferay Symposium Italy, Rome 2014- 25 -

Liferay Plugins SDK - Required context

● I servizi sono dichiarati nel file “service.xml”● Possono gestire entità reali (tabelle a

database) <entity name="FavoriteSite" local-service="true" remote-service="false"> <column name="favoriteSiteId" type="long" primary="true" /> <column name="groupId" type="long" /> <column name="companyId" type="long" />

● Oppure entità “di servizio” <entity name="SocialOffice" local-service="false" remote-service="true"> <!-- References --> <reference package-path="com.liferay.portal" entity="Group" /> </entity>

Liferay Symposium Italy, Rome 2014- 26 -

Liferay Plugins SDK - Required context

● Dichiaro delle entità di servizio per gli elementi CRM (es: CRMProductService*)

● Sfrutto il required-deployment-contexts per fornire i servizi agli altri plugins

Liferay Symposium Italy, Rome 2014- 27 -

Problematiche risolte

✔ Gestire il codice di integrazione con OpenCRX in una libreria riusabile da più plugins

✔ Concentrare l'accesso al CRM in un unico plugin

Liferay Symposium Italy, Rome 2014- 28 -

Liferay Plugins SDK - Required context

I metodi dei services devono ritornare i dati del CRM

Come evitare che Bean complessi mi sollevino una ClassCastException?

Liferay Symposium Italy, Rome 2014- 29 -

Liferay Plugins SDK - Required context

● I servizi devono ritornare oggetti semplici (int, long, String)– gli oggetti complessi sono JSON

● Ho bisogno di un ulteriore strato che:– Dichiari i POJO delle entità CRM (es: CRMProduct)– Si preoccupi di convertire gli oggetti JSON in POJO

(es: CRMProductUtil)

Liferay Symposium Italy, Rome 2014- 30 -

Problematiche risolte

✔ Gestire il codice di integrazione con OpenCRX in una libreria riusabile da più plugins

✔ Concentrare l'accesso al CRM in un unico plugin

✔ Gestire gli elementi CRM come oggetti complessi

Liferay Symposium Italy, Rome 2014- 31 -

Problematica – Sovraccarico CRM

Come evitare di sovraccaricare il CRM con troppe richieste contemporanee?

Liferay Symposium Italy, Rome 2014- 32 -

Problematica – Sovraccarico CRM

Come evitare di sovraccaricare il CRM con troppe richieste contemporanee?

Creando qualcosa di simile ad un connection-pool.

Uso il MessageBus per creare delle code di elaborazione.

Liferay Symposium Italy, Rome 2014- 33 -

MessageBus

● E' un framework sviluppato da Liferay per gestire code di messaggi.

● E' stato realizzato per essere leggero e flessibile.

● Non si appoggia ad alcun framework esterno● Composto da tre elementi principali

– Il Messaggio– La Destinazione (dove viene recapitato il

messaggio)– Il Listener (l'attore che elabora il Messaggio)

Liferay Symposium Italy, Rome 2014- 34 -

MessageBus

Le Destinazioni sono● Asincrone: utilizzano più worker per elaborare i

messaggi– Seriale: dispacciano il Messaggio ad un Listener alla volta– Parallela: dispacciano il Messaggio su più Listener

contemporaneamente

● Sincrone: utilizzano un singolo worker

com....kernel.messaging.SerialDestination

com....kernel.messaging.ParallelDestination

com....kernel.messaging.SynchronousDestination

Liferay Symposium Italy, Rome 2014- 35 -

MessageBus

L'invio dei messaggi può essere:● Sincrono

– il processo sender rimane appeso in attesa di una risposta– finché non arriva o per un periodo di tempo certo (timeout)

● Asincrono– il processo sender continua– posso indicare un callback su cui ricevere la risposta– Posso “inviare e dimenticare”

MessageBusUtil.sendMessage(destination, payload)

MessageBusUtil.SendSyncronousMessage(destination, payload)

Liferay Symposium Italy, Rome 2014- 36 -

Problematica – Sovraccarico CRM

Il plugin “crm-integration-web”● Implementa il dialogo con il CRM● Tramite il ServiceBuilder gestisce le entità CRM come entità “di

servizio”– Sotto forma di oggetti JSON

● Dichiara delle MessageBus Destination per creare delle code di accesso ai servizi generati dal ServiceBuilder

Il plugin “crm-integration-shared”● Dichiara / Implementa i Bean delle entità CRM● Implementa le classi per interagire con il MessageBus

– Inviare i messaggi– Trasformare le risposte JSON (Payload) in POJO

Liferay Symposium Italy, Rome 2014- 37 -

Problematica – Sovraccarico CRM

Plugin ONE

crm-integration-shared

Plugin TWO

crm-integration-shared

crm-integration-web

Destination

Destination

Service

Destination

Listener

Listener

Listener

CRM

Liferay Symposium Italy, Rome 2014- 38 -

Caching strato servizi

Posso fare di più?

Cache!

Per le entità reali il ServiceBuilder genera la classe xxxPersistenceImpl che sfrutta la MultiVMPoolUtil per gestire la cache dei Model e dei Finder

Liferay Symposium Italy, Rome 2014- 39 -

Caching strato servizi

Per le entità “di servizio” questa classe non c'è.

Ma la posso creare.

Devo creare sia l'interfaccia nella parte service

public interface CrmProductPersistence {

public int countByC_P_D_C_B_TT(

long userId, String customerId, String productNumber,

String description, String categoryId, String brandId,

CrmProductSearchTerms terms)

throws CrmComunicationException, CrmResponseException;

Liferay Symposium Italy, Rome 2014- 40 -

Caching strato servizi

Ed ovviamente la sua implementazione

public class CrmProductPersistenceImpl extends CrmBasePersistenceImpl implements CrmProductPersistence {.... public List<String> findByDescription( long userId, String customerId, String productNumber, String description, String categoryId, String brandId, CrmProductSearchTerms terms, Locale locale, int start, int count) throws CrmComunicationException, CrmResponseException {

Object[] finderArgs = new Object[] { productNumber, description, categoryId, brandId, terms, start, count, locale};

@SuppressWarnings("unchecked") List<String> list = (List<String>)FinderCacheUtil.getResult( FINDER_PATH_FIND_BY_DESCRIPTION, finderArgs, null);

if (list == null) { ... list = crmItemsValuesFromResponse(productsResponse);

if ((list != null) && !list.isEmpty()) { FinderCacheUtil.putResult(FINDER_PATH_FIND_BY_DESCRIPTION, finderArgs, list); } }

return list; }

Liferay Symposium Italy, Rome 2014- 41 -

Caching strato servizi

La configurazione della cache si trova in “portal-impl/src/ehcache”

Liferay Symposium Italy, Rome 2014- 42 -

Problematiche risolte

✔ Gestire il codice di integrazione con OpenCRX in una libreria riusabile da più plugins

✔ Concentrare l'accesso al CRM in un unico plugin

✔ Gestire gli elementi CRM come oggetti complessi

✔ Ridurre sovraccarico CRM (code + cache)

Liferay Symposium Italy, Rome 2014- 43 -

Problematica - cluster

● E se ho una installazione Liferay in Cluster?● La cache di Liferay è di tipo “Invalidante”

– Se un dato non è presente in cache, oppure è scaduto o invalidato

● lo leggo e lo metto nella mia cache

– Se modifico un dato● Lo salvo sul DB● Lo aggiorno nella mia cache● Informo gli altri nodi di invalidarlo nella loro cache

– Se cancello un dato● Lo cancello dal DB● Lo invalido nalla mia cache● Informo gli altri nodi di invalidarlo nella loro cache

Liferay Symposium Italy, Rome 2014- 44 -

Problematica - cluster

Possibilità UNO: dichiaro una specifica cache di replica nel MultiVMPoolUtil

<cache eternal="false" maxElementsInMemory="100000" name="it.smc.....CRMProduct" overflowToDisk="false" timeToIdleSeconds="600"> <cacheEventListenerFactory class="com....ehcache.LiferayCacheEventListenerFactory" properties="replicatePuts=false,replicateUpdatesViaCopy=false" propertySeparator="," /> <bootstrapCacheLoaderFactory class="com....ehcache.LiferayBootstrapCacheLoaderFactory" /></cache>

"replicatePuts=true,replicatePutsViaCopy=true,replicateUpdatesViaCopy=true"

Liferay Symposium Italy, Rome 2014- 45 -

Problematica - cluster

Possibilità DUE: Uso la SingleVMPoolUtil e decido io come propagare la cache tra i nodi.

Per propagarla utilizzo il framework “ClusterExecutor”

Liferay Symposium Italy, Rome 2014- 46 -

Problematica - cluster

com.liferay.portal.kernel.cluster.ClusterExecutorUtil

public List<ClusterNode> getClusterNodes(); public ClusterNode getLocalClusterNode() throws SystemException; public Address getLocalClusterNodeAddress(); public void initialize(); public boolean isClusterNodeAlive(Address address); public boolean isClusterNodeAlive(String clusterNodeId); public boolean isEnabled();

public FutureClusterResponses execute( ClusterRequest clusterRequest) throws SystemException;

Liferay Symposium Italy, Rome 2014- 47 -

Problematica - cluster

Il metodo Execute mi permette di eseguire un metodo di una classe negli altri nodi● Identifico il metodo da chiamareMethodKey myMethodKey = new MethodKey( MethodClass.class, "methodName", FirstSerializableArguement.class ...);

● Creo l'handler del metodoMethodHandler myMethodHandler = new MethodHandler( myMethodKey, myFirstArguement....);

● Lo invoco– Metto true su skipLocal per saltare me stesso

ClusterRequest clusterRequest = ClusterRequest.createMulticastRequest( methodHandler, true);ClusterExecutorUtil.execute(clusterRequest);

Liferay Symposium Italy, Rome 2014- 48 -

Problematiche risolte

✔ Gestire il codice di integrazione con OpenCRX in una libreria riusabile da più plugins

✔ Concentrare l'accesso al CRM in un unico plugin

✔ Gestire gli elementi CRM come oggetti complessi

✔ Ridurre sovraccarico CRM (code + cache)✔ Gestire installazione in Cluster

Liferay Symposium Italy, Rome 2014- 49 -

MessageBus, Cluster communication and caching on B2B

Mariuzzo MauroLiferay Architect, SMC Treviso srl